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

org.apache.drill.exec.compile.ClassCompilerSelector Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 */
package org.apache.drill.exec.compile;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.exceptions.UserException;
import org.apache.drill.exec.compile.ClassTransformer.ClassNames;
import org.apache.drill.exec.exception.ClassTransformationException;
import org.apache.drill.exec.server.options.OptionMetaData;
import org.apache.drill.exec.server.options.OptionSet;
import org.apache.drill.exec.server.options.OptionValidator;
import org.apache.drill.exec.server.options.OptionValidator.OptionDescription;
import org.apache.drill.exec.server.options.OptionValue;
import org.apache.drill.exec.server.options.TypeValidators.BooleanValidator;
import org.apache.drill.exec.server.options.TypeValidators.LongValidator;
import org.apache.drill.exec.server.options.TypeValidators.StringValidator;
import org.codehaus.commons.compiler.CompileException;

/**
 * Selects between the two supported Java compilers: Janino and
 * the build-in Java compiler.
 *
 * 

Session Options

*
*
exec.java_compiler
*
The compiler to use. Valid options are defined in the * {@link ClassCompilerSelector.CompilerPolicy} enum.
*
exec.java_compiler_debug
*
If debug logging is enabled, then {@link AbstractClassCompiler} writes the * generated Java code to the log file prior to compilation. This option * adds line numbers to the logged code.
*
exec.java_compiler_janino_maxsize
*
The maximum size of code that the Janino compiler can handle. Larger code is * handled by the JDK compiler. Defaults to 256K.
*
*

Configuration Options

* Configuration options are used when the above session options are unset. *
*
drill.exec.compile.compiler
*
Default for exec.java_compiler
*
drill.exec.compile.debug
*
Default for exec.java_compiler_debug
*
drill.exec.compile.janino_maxsize
*
Default for exec.java_compiler_janino_maxsize
*
*/ public class ClassCompilerSelector { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ClassCompilerSelector.class); public enum CompilerPolicy { DEFAULT, JDK, JANINO; } public static final String JAVA_COMPILER_JANINO_MAXSIZE_CONFIG = CodeCompiler.COMPILE_BASE + ".janino_maxsize"; public static final String JAVA_COMPILER_DEBUG_CONFIG = CodeCompiler.COMPILE_BASE + ".debug"; public static final String JAVA_COMPILER_CONFIG = CodeCompiler.COMPILE_BASE + ".compiler"; public static final String JAVA_COMPILER_OPTION = "exec.java_compiler"; public static final String JAVA_COMPILER_JANINO_MAXSIZE_OPTION = "exec.java_compiler_janino_maxsize"; public static final OptionValidator JAVA_COMPILER_JANINO_MAXSIZE = new LongValidator(JAVA_COMPILER_JANINO_MAXSIZE_OPTION, new OptionDescription("See the exec.java_compiler option comment. Accepts inputs of type LONG.")); public static final String JAVA_COMPILER_DEBUG_OPTION = "exec.java_compiler_debug"; public static final OptionValidator JAVA_COMPILER_DEBUG = new BooleanValidator(JAVA_COMPILER_DEBUG_OPTION, new OptionDescription("Toggles the output of debug-level compiler error messages in runtime generated code.")); public static final StringValidator JAVA_COMPILER_VALIDATOR = new StringValidator(JAVA_COMPILER_OPTION, new OptionDescription("Switches between DEFAULT, JDK, and JANINO mode for the current session. Uses Janino by default for generated source code of less than exec.java_compiler_janino_maxsize; otherwise, switches to the JDK compiler.")) { @Override public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) { super.validate(v, metaData, manager); try { CompilerPolicy.valueOf(v.string_val.toUpperCase()); } catch (IllegalArgumentException e) { throw UserException.validationError() .message("Invalid value '%s' specified for option '%s'. Valid values are %s.", v.string_val, getOptionName(), Arrays.toString(CompilerPolicy.values())) .build(QueryClassLoader.logger); } } }; private final CompilerPolicy policy; private final long janinoThreshold; private final AbstractClassCompiler jdkClassCompiler; private final AbstractClassCompiler janinoClassCompiler; public ClassCompilerSelector(ClassLoader classLoader, DrillConfig config, OptionSet sessionOptions) { OptionValue value = sessionOptions.getOption(JAVA_COMPILER_OPTION); policy = CompilerPolicy.valueOf((value != null) ? value.string_val.toUpperCase() : config.getString(JAVA_COMPILER_CONFIG).toUpperCase()); value = sessionOptions.getOption(JAVA_COMPILER_JANINO_MAXSIZE_OPTION); janinoThreshold = (value != null) ? value.num_val : config.getLong(JAVA_COMPILER_JANINO_MAXSIZE_CONFIG); value = sessionOptions.getOption(JAVA_COMPILER_DEBUG_OPTION); boolean debug = (value != null) ? value.bool_val : config.getBoolean(JAVA_COMPILER_DEBUG_CONFIG); janinoClassCompiler = (policy == CompilerPolicy.JANINO || policy == CompilerPolicy.DEFAULT) ? new JaninoClassCompiler(classLoader, debug) : null; jdkClassCompiler = (policy == CompilerPolicy.JDK || policy == CompilerPolicy.DEFAULT) ? JDKClassCompiler.newInstance(classLoader, debug) : null; logger.info(String.format("Java compiler policy: %s, Debug option: %b", policy, debug)); } byte[][] getClassByteCode(ClassNames className, String sourceCode) throws CompileException, ClassNotFoundException, ClassTransformationException, IOException { byte[][] bc = getCompiler(sourceCode).getClassByteCode(className, sourceCode); // Uncomment the following to save the generated byte codes. // Use the JDK javap command to view the generated code. // This is the code from the compiler before byte code manipulations. // For a similar block to display byte codes after manipulation, // see QueryClassLoader. // final File baseDir = new File( new File( System.getProperty("java.io.tmpdir") ), "classes" ); // for ( int i = 0; i < bc.length; i++ ) { // File classFile = new File( baseDir, className.slash + i + ".class" ); // classFile.getParentFile().mkdirs(); // try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(classFile))) { // out.write(bc[i]); // } // } // System.out.println( "Classes saved to: " + baseDir.getAbsolutePath() ); return bc; } public Map compile(ClassNames className, String sourceCode) throws CompileException, ClassNotFoundException, ClassTransformationException, IOException { return getCompiler(sourceCode).compile(className, sourceCode); } private AbstractClassCompiler getCompiler(String sourceCode) { if (jdkClassCompiler != null && (policy == CompilerPolicy.JDK || (policy == CompilerPolicy.DEFAULT && sourceCode.length() > janinoThreshold))) { return jdkClassCompiler; } else { return janinoClassCompiler; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy