| /* |
| * 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.myfaces.extensions.scripting.core.engine.compiler; |
| |
| import org.apache.myfaces.extensions.scripting.core.api.Configuration; |
| import org.apache.myfaces.extensions.scripting.core.api.WeavingContext; |
| import org.apache.myfaces.extensions.scripting.core.common.util.ClassLoaderUtils; |
| import org.apache.myfaces.extensions.scripting.core.common.util.FileUtils; |
| import org.apache.myfaces.extensions.scripting.core.engine.api.CompilationMessage; |
| import org.apache.myfaces.extensions.scripting.core.engine.api.CompilationResult; |
| |
| import javax.tools.Diagnostic; |
| import javax.tools.DiagnosticCollector; |
| import javax.tools.JavaFileManager; |
| import javax.tools.JavaFileObject; |
| import javax.tools.StandardJavaFileManager; |
| import javax.tools.ToolProvider; |
| import java.io.File; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import static org.apache.myfaces.extensions.scripting.core.api.ScriptingConst.ENGINE_TYPE_JSF_JAVA; |
| import static org.apache.myfaces.extensions.scripting.core.engine.api.CompilerConst.*; |
| |
| /** |
| * @author Werner Punz (latest modification by $Author$) |
| * @version $Revision$ $Date$ |
| * <p/> |
| * a JSR 199 based compiler which implements |
| * our simplified compiler interface |
| */ |
| public class JSR199Compiler implements org.apache.myfaces.extensions.scripting.core.engine.api.Compiler |
| { |
| |
| javax.tools.JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); |
| StandardJavaFileManager fileManager = null; |
| |
| |
| public JSR199Compiler() |
| { |
| super(); |
| } |
| |
| /** |
| * compile all files starting from a given root |
| * <p/> |
| * note, the java compiler interface does not allow per se |
| * wildcards due to its file object indirection |
| * we deal with that problem by determine all files manually and then |
| * push the list into the jsr compiler interface |
| * |
| * |
| * @param sourceRoot the root for all java sources to be compiled |
| * @param loader the classpath holder for the compilation |
| * @return the collected compilation results as bundle |
| */ |
| public CompilationResult compile(File sourceRoot, File destination, ClassLoader loader) { |
| WeavingContext context = WeavingContext.getInstance(); |
| Configuration configuration = context.getConfiguration(); |
| destination.mkdirs(); |
| fileManager = javaCompiler.getStandardFileManager(new |
| DiagnosticCollector<JavaFileObject>(), Locale.getDefault(), null); |
| |
| DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>(); |
| |
| getLog().info("[EXT-SCRIPTING] Doing a full recompile"); |
| |
| List<File> sourceFiles = FileUtils.fetchSourceFiles(configuration.getWhitelistedSourceDirs |
| (ENGINE_TYPE_JSF_JAVA), JAVA_WILDCARD); |
| |
| HashSet<String> alreadyProcessed = new HashSet<String>(); |
| Iterator<File> sourceIt = sourceFiles.iterator(); |
| while(sourceIt.hasNext()) { |
| File currentProcessed = sourceIt.next(); |
| if(alreadyProcessed.contains(currentProcessed.getAbsolutePath())) { |
| sourceIt.remove(); |
| } else { |
| alreadyProcessed.add(currentProcessed.getAbsolutePath()); |
| } |
| |
| } |
| |
| |
| for (File sourceFile : sourceFiles) |
| { |
| if (!sourceFile.exists()) |
| { |
| getLog().log(Level.WARNING, "[EXT-SCRIPTING] Source file with path {0} does not exist it might cause an error in the compilation process", sourceFile.getAbsolutePath()); |
| } |
| } |
| Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(sourceFiles.toArray(new File[sourceFiles.size()])); |
| String[] options = new String[]{JC_CLASSPATH, /*fileManager.getClassPath()*/ |
| ClassLoaderUtils.buildClasspath(ClassLoaderUtils.getDefaultClassLoader()) |
| , JC_TARGET_PATH, |
| destination.getAbsolutePath(), JC_SOURCEPATH, |
| sourceRoot.getAbsolutePath(), JC_DEBUG}; |
| |
| javaCompiler.getTask(null, fileManager, diagnosticCollector, Arrays.asList(options), null, fileObjects).call(); |
| |
| |
| CompilationResult result = handleDiagnostics(diagnosticCollector); |
| |
| |
| return result; |
| |
| } |
| |
| /** |
| * internal diagnostics handler |
| * which just logs the errors |
| * |
| * @param diagnosticCollector the compilation results, the jsr 199 uses a DiagnosticsCollector object |
| * to keep the errors and warnings of the compiler |
| * @throws ClassNotFoundException in case of an error (this is enforced by the compiler interface |
| * and probably will be overhauled in the long run) |
| */ |
| private CompilationResult handleDiagnostics(DiagnosticCollector<JavaFileObject> diagnosticCollector) |
| { |
| if (diagnosticCollector.getDiagnostics().size() > 0) |
| { |
| Logger log = Logger.getLogger(this.getClass().getName()); |
| StringBuilder errors = new StringBuilder(); |
| CompilationResult result = new CompilationResult(""); |
| boolean hasError = false; |
| for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) |
| { |
| String error = createErrorMessage(diagnostic); |
| log.log(Level.WARNING, "[EXT-SCRIPTING] Compiler: {0}", error); |
| |
| if (diagnostic.getKind().equals(Diagnostic.Kind.ERROR)) |
| { |
| hasError = true; |
| result.getErrors().add(new CompilationMessage(diagnostic.getLineNumber(), diagnostic.getMessage(Locale.getDefault()))); |
| } else |
| { |
| result.getWarnings().add(new CompilationMessage(diagnostic.getLineNumber(), diagnostic.getMessage(Locale.getDefault()))); |
| } |
| errors.append(error); |
| |
| } |
| return result; |
| } else |
| { |
| //WeavingContext.setCompilationResult(ENGINE_TYPE_JSF_JAVA, new CompilationResult("")); |
| return new CompilationResult(""); |
| } |
| } |
| |
| /** |
| * interruption of the compile flow should only |
| * happen if an error has occurred otherwise we will proceed |
| * as expected |
| * |
| * @param errors the errors messages found |
| * @param hasError marker if an error was found or not |
| * @throws ClassNotFoundException in case of a compile error |
| */ |
| private void assertErrorFound(StringBuilder errors, boolean hasError) throws ClassNotFoundException |
| { |
| if (hasError) |
| { |
| throw new ClassNotFoundException("Compile error of java file:" + errors.toString()); |
| } |
| } |
| |
| /** |
| * creates a standardized error message |
| * |
| * @param diagnostic the diagnostic of the compiler containing the error data |
| * @return a formatted string with the standardized error message which then later |
| * can be processed by the user |
| */ |
| private String createErrorMessage(Diagnostic diagnostic) |
| { |
| StringBuilder retVal = new StringBuilder(256); |
| if (diagnostic == null) |
| { |
| return retVal.toString(); |
| } |
| if (diagnostic.getKind().equals(Diagnostic.Kind.ERROR)) |
| { |
| retVal.append(STD_ERROR_HEAD); |
| } else if (diagnostic.getKind().equals(Diagnostic.Kind.NOTE)) |
| { |
| retVal.append(STD_NOTE_HEAD); |
| } else if (diagnostic.getKind().equals(Diagnostic.Kind.WARNING)) |
| { |
| retVal.append(STD_WARN_HEAD); |
| } else if (diagnostic.getKind().equals(Diagnostic.Kind.MANDATORY_WARNING)) |
| { |
| retVal.append(STD_MANDATORY_WARN_HEAD); |
| } else if (diagnostic.getKind().equals(Diagnostic.Kind.OTHER)) |
| { |
| retVal.append(STD_OTHER_HEAD); |
| } |
| String message = diagnostic.getMessage(Locale.getDefault()); |
| message = (message == null) ? "" : message; |
| retVal.append(message); |
| retVal.append(diagnostic.getLineNumber()); |
| |
| retVal.append("\n\n"); |
| |
| String source = "No additional source info"; |
| |
| if (diagnostic.getSource() != null) |
| { |
| source = diagnostic.getSource().toString(); |
| } |
| retVal.append(source); |
| |
| return retVal.toString(); |
| } |
| |
| private Logger getLog() |
| { |
| return Logger.getLogger(this.getClass().getName()); |
| } |
| |
| } |