All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scriptella.driver.janino.CodeCompiler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2006-2012 The Scriptella Project Team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package scriptella.driver.janino;

import org.codehaus.commons.compiler.LocatedException;
import org.codehaus.janino.ScriptEvaluator;
import scriptella.expression.LineIterator;
import scriptella.spi.Resource;
import scriptella.util.ExceptionUtils;
import scriptella.util.IOUtils;

import java.io.IOException;
import java.io.Reader;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Compiles Janino scripts.
 *
 * @author Fyodor Kupolov
 * @version 1.0
 */
final class CodeCompiler {
    private static final Logger LOG = Logger.getLogger(CodeCompiler.class.getName());
    private static final boolean DEBUG = LOG.isLoggable(Level.FINE);
    //Allowed exceptions to be thrown by a script
    private static final Class[] THROWN_EXCEPTIONS = new Class[]{Exception.class};
    //Compiled scripts(Static methods) cache
    private Map objectCache = new IdentityHashMap();

    public JaninoScript compileScript(final Resource resource) {
        return (JaninoScript) compile(resource, false);
    }

    public JaninoQuery compileQuery(final Resource resource) {
        return (JaninoQuery) compile(resource, true);
    }

    private Object compile(final Resource content, final boolean query) {
        Object ctx = objectCache.get(content);
        if (ctx == null) {
            ScriptEvaluator evaluator = new ScriptEvaluator();
            //Exception are not required to be handled
            evaluator.setThrownExceptions(THROWN_EXCEPTIONS);
            evaluator.setParentClassLoader(getClass().getClassLoader());
            Class type = query ? JaninoQuery.class : JaninoScript.class;
            evaluator.setExtendedType(type);
            evaluator.setStaticMethod(false);
            evaluator.setMethodName("execute");
            evaluator.setClassName(type.getName() + "_Generated");
            if (DEBUG) {
                evaluator.setDebuggingInformation(true, true, true);
            }

            Reader r = null;
            try {
                r = content.open();
                evaluator.cook(content.toString(), r);
            } catch (Exception e) {
                throw guessErrorStatement(new JaninoProviderException("Compilation failed", e), content);
            } finally {
                IOUtils.closeSilently(r);
            }
            Class cl = evaluator.getMethod().getDeclaringClass();
            try {
                ctx = cl.newInstance();
            } catch (Exception e) {
                throw new JaninoProviderException("Unable to instantiate compiled class", e);
            }
            objectCache.put(content, ctx);
        }
        return ctx;
    }

    /**
     * Finds error statement which caused compilation error.
     */
    private static JaninoProviderException guessErrorStatement(JaninoProviderException pe, Resource r) {
        Throwable cause = pe.getCause();
        try {
            if (cause instanceof LocatedException) {
                LocatedException le = (LocatedException) cause;
                if (le.getLocation() != null) {
                    String line = getLine(r, le.getLocation().getLineNumber());
                    pe.setErrorStatement(line);
                }
            }
        } catch (NoClassDefFoundError e) {
            //BUG-36290 Error with Janino 2.6.0
            LOG.severe("Error statement cannot be determined due to " + e + ". Try upgrading Janino to version 2.6 or newer.");
        }
        return pe;
    }

    static String getLine(Resource resource, int line) {
        //Line number can be undefined
        if (line < 0) {
            return null;
        }
        LineIterator it = null;
        try {
            it = new LineIterator(resource.open());
            return it.getLineAt(line - 1);
        } catch (IOException e) {
            ExceptionUtils.ignoreThrowable(e);
        } finally {
            IOUtils.closeSilently(it);
        }
        return null;
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy