package org.elasticsearch.plan.a;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.SecureClassLoader;
import java.security.cert.Certificate;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.
*/
import java.util.Properties;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.elasticsearch.bootstrap.BootstrapInfo;
import static org.elasticsearch.plan.a.Default.*;
import static org.elasticsearch.plan.a.Definition.*;
final class Compiler {
/** we define the class with lowest privileges */
private static final CodeSource CODESOURCE;
static {
try {
CODESOURCE = new CodeSource(new URL("file:" + BootstrapInfo.UNTRUSTED_CODEBASE), (Certificate[]) null);
} catch (MalformedURLException impossible) {
throw new RuntimeException(impossible);
}
}
private static class Loader extends SecureClassLoader {
Loader(ClassLoader parent) {
super(parent);
}
Class<? extends Executable> define(String name, byte[] bytes) {
return defineClass(name, bytes, 0, bytes.length, CODESOURCE).asSubclass(Executable.class);
}
}
static Executable compile(final String name, final String source,
final ClassLoader parent, final Properties properties) {
long start = System.currentTimeMillis();
final Definition definition = properties == null ? DEFAULT_DEFINITION : loadFromProperties(properties);
final Standard standard = properties == null ? DEFAULT_STANDARD : new Standard(definition);
final Caster caster = properties == null ? DEFAULT_CASTER : new Caster(definition, standard);
//long end = System.currentTimeMillis() - start;
//System.out.println("definition: " + end);
//start = System.currentTimeMillis();
//final ParserRuleContext root = createParseTree(source, definition);
final ANTLRInputStream stream = new ANTLRInputStream(source);
final ErrorHandlingLexer lexer = new ErrorHandlingLexer(stream);
final PlanAParser parser = new PlanAParser(new CommonTokenStream(lexer));
final ParserErrorStrategy strategy = new ParserErrorStrategy();
lexer.removeErrorListeners();
parser.setTypes(definition.structs.keySet());
parser.removeErrorListeners();
parser.setErrorHandler(strategy);
ParserRuleContext root = parser.source();
//end = System.currentTimeMillis() - start;
//System.out.println("tree: " + end);
final Adapter adapter = new Adapter(definition, standard, caster, source, root);
adapter.incrementScope();
adapter.addVariable(null, "this", adapter.standard.execType);
adapter.addVariable(null, "input", adapter.standard.smapType);
start = System.currentTimeMillis();
Analyzer.analyze(adapter);
adapter.decrementScope();
// System.out.println(root.toStringTree(parser));
//end = System.currentTimeMillis() - start;
//System.out.println("analyze: " + end);
//start = System.currentTimeMillis();
final byte[] bytes = Writer.write(adapter);
//end = System.currentTimeMillis() - start;
//System.out.println("write: " + end);
//start = System.currentTimeMillis();
final Executable executable = createExecutable(name, source, parent, bytes);
//end = System.currentTimeMillis() - start;
//System.out.println("create: " + end);
return executable;
}
private static ParserRuleContext createParseTree(String source, Definition definition) {
final ANTLRInputStream stream = new ANTLRInputStream(source);
final ErrorHandlingLexer lexer = new ErrorHandlingLexer(stream);
final PlanAParser parser = new PlanAParser(new CommonTokenStream(lexer));
final ParserErrorStrategy strategy = new ParserErrorStrategy();
lexer.removeErrorListeners();
parser.setTypes(definition.structs.keySet());
parser.removeErrorListeners();
parser.setErrorHandler(strategy);
ParserRuleContext root = parser.source();
// System.out.println(root.toStringTree(parser));
return root;
}
private static Executable createExecutable(String name, String source, ClassLoader parent, byte[] bytes) {
try {
// for debugging:
//try {
// FileOutputStream f = new FileOutputStream(new File("/Users/jdconrad/lang/generated/out.class"), false);
// f.write(bytes);
// f.close();
//} catch (Exception e) {
// throw new RuntimeException(e);
//}
final Loader loader = new Loader(parent);
final Class<? extends Executable> clazz = loader.define(Writer.CLASS_NAME, bytes);
final java.lang.reflect.Constructor<? extends Executable> constructor =
clazz.getConstructor(String.class, String.class);
return constructor.newInstance(name, source);
} catch (Exception exception) {
throw new IllegalStateException(
"An internal error occurred attempting to define the script [" + name + "].", exception);
}
}
private Compiler() {}
}