/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * 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.drools.compiler.rule.builder.dialect.java; import org.drools.compiler.builder.impl.KnowledgeBuilderConfigurationImpl; import org.drools.compiler.compiler.Dialect; import org.drools.compiler.compiler.DialectConfiguration; import org.drools.compiler.compiler.PackageRegistry; import org.drools.core.definitions.InternalKnowledgePackage; import org.drools.core.rule.builder.dialect.asm.ClassLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import static org.mvel2.asm.Opcodes.V1_5; import static org.mvel2.asm.Opcodes.V1_6; import static org.mvel2.asm.Opcodes.V1_7; import static org.mvel2.asm.Opcodes.V1_8; /** * * There are options to use various flavours of runtime compilers. * Apache JCI is used as the interface to all the runtime compilers. * * You can also use the system property "drools.compiler" to set the desired compiler. * The valid values are "ECLIPSE" and "JANINO" only. * * drools.dialect.java.compiler = <ECLIPSE|JANINO> * drools.dialect.java.compiler.lnglevel = <1.5|1.6> * * The default compiler is Eclipse and the default lngLevel is 1.5. * The lngLevel will attempt to autodiscover your system using the * system property "java.version" * * The JavaDialectConfiguration will attempt to validate that the specified compiler * is in the classpath, using ClassLoader.loasClass(String). If you intented to * just Janino sa the compiler you must either overload the compiler property before * instantiating this class or the PackageBuilder, or make sure Eclipse is in the * classpath, as Eclipse is the default. */ public class JavaDialectConfiguration implements DialectConfiguration { protected static final transient Logger logger = LoggerFactory.getLogger(JavaDialectConfiguration.class); public static final String JAVA_COMPILER_PROPERTY = "drools.dialect.java.compiler"; public static final int ECLIPSE = 0; public static final int JANINO = 1; public static final int NATIVE = 2; public static final String[] LANGUAGE_LEVELS = new String[]{"1.5", "1.6", "1.7", "1.8"}; private String languageLevel; private KnowledgeBuilderConfigurationImpl conf; private int compiler; public JavaDialectConfiguration() { } public void init(final KnowledgeBuilderConfigurationImpl conf) { this.conf = conf; setCompiler( getDefaultCompiler() ); setJavaLanguageLevel( getDefaultLanguageLevel() ); } public KnowledgeBuilderConfigurationImpl getPackageBuilderConfiguration() { return this.conf; } public Dialect newDialect(ClassLoader rootClassLoader, KnowledgeBuilderConfigurationImpl pkgConf, PackageRegistry pkgRegistry, InternalKnowledgePackage pkg) { return new JavaDialect(rootClassLoader, pkgConf, pkgRegistry, pkg); } public String getJavaLanguageLevel() { return this.languageLevel; } /** * You cannot set language level below 1.5, as we need static imports, 1.5 is now the default. * @param languageLevel */ public void setJavaLanguageLevel(final String languageLevel) { if ( Arrays.binarySearch( LANGUAGE_LEVELS, languageLevel ) < 0 ) { throw new RuntimeException( "value '" + languageLevel + "' is not a valid language level" ); } this.languageLevel = languageLevel; } /** * Set the compiler to be used when building the rules semantic code blocks. * This overrides the default, and even what was set as a system property. */ public void setCompiler(final int compiler) { // check that the jar for the specified compiler are present if ( compiler == ECLIPSE ) { try { Class.forName( "org.eclipse.jdt.internal.compiler.Compiler", true, this.conf.getClassLoader() ); } catch ( ClassNotFoundException e ) { throw new RuntimeException( "The Eclipse JDT Core jar is not in the classpath" ); } } else if ( compiler == JANINO ){ try { Class.forName( "org.codehaus.janino.Parser", true, this.conf.getClassLoader() ); } catch ( ClassNotFoundException e ) { throw new RuntimeException( "The Janino jar is not in the classpath" ); } } switch ( compiler ) { case ECLIPSE : this.compiler = ECLIPSE; break; case JANINO : this.compiler = JANINO; break; case NATIVE : this.compiler = NATIVE; break; default : throw new RuntimeException( "value '" + compiler + "' is not a valid compiler" ); } } public int getCompiler() { return this.compiler; } /** * This will attempt to read the System property to work out what default to set. * This should only be done once when the class is loaded. After that point, you will have * to programmatically override it. */ private int getDefaultCompiler() { try { final String prop = this.conf.getChainedProperties().getProperty( JAVA_COMPILER_PROPERTY, "ECLIPSE" ); if ( prop.equals( "NATIVE" ) ) { return NATIVE; } else if ( prop.equals( "ECLIPSE" ) ) { return ECLIPSE; } else if ( prop.equals( "JANINO" ) ) { return JANINO; } else { logger.error( "Drools config: unable to use the drools.compiler property. Using default. It was set to:" + prop ); return ECLIPSE; } } catch ( final SecurityException e ) { logger.error( "Drools config: unable to read the drools.compiler property. Using default.", e); return ECLIPSE; } } private String getDefaultLanguageLevel() { switch (ClassLevel.findJavaVersion(this.conf.getChainedProperties())) { case V1_5: return "1.5"; case V1_6: return "1.6"; case V1_7: return "1.7"; case V1_8: return "1.8"; default: return "1.7"; } } }