blob: d84349d7aeee65c8f88e4bf20967caa2f77a96c4 [file] [log] [blame]
/*
* 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.compiler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.extensions.scripting.loader.ClassLoaderUtils;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.ErrorCollector;
import org.codehaus.groovy.control.messages.Message;
import org.codehaus.groovy.control.messages.SimpleMessage;
import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* <p>A compiler implementation that can be used to compile Groovy source files.</p>
*
*/
public class GroovyCompiler implements Compiler {
/**
* The logger instance for this class.
*/
private static final Log logger = LogFactory.getLog(GroovyCompiler.class);
// ------------------------------------------ Compiler methods
/**
* <p>Compiles the given file and creates an according class file in the given target path.</p>
*
* @param sourcePath the path to the source directory
* @param targetPath the path to the target directory
* @param file the file of the class you want to compile
* @param classLoader the class loader to use to determine the classpath
* @return the compilation result
*/
public CompilationResult compile(File sourcePath, File targetPath, String file, ClassLoader classLoader)
throws CompilationException {
return compile(sourcePath, targetPath, new File(sourcePath, file), classLoader);
}
/**
* <p>Compiles the given file and creates an according class file in the given target path.</p>
*
* @param sourcePath the path to the source directory
* @param targetPath the path to the target directory
* @param file the file of the class you want to compile
* @param classLoader the class loader to use to determine the classpath
* @return the compilation result
*/
public CompilationResult compile(File sourcePath, File targetPath, File file, ClassLoader classLoader)
throws CompilationException {
StringWriter compilerOutput = new StringWriter();
CompilationUnit compilationUnit = new CompilationUnit(
buildCompilerConfiguration(sourcePath, targetPath, classLoader));
compilationUnit.getConfiguration().setOutput(new PrintWriter(compilerOutput));
compilationUnit.addSource(file);
CompilationResult result;
try {
compilationUnit.compile();
result = new CompilationResult(compilerOutput.toString());
} catch (CompilationFailedException ex) {
// Register all collected error messages from the Groovy compiler
result = new CompilationResult(compilerOutput.toString());
ErrorCollector collector = compilationUnit.getErrorCollector();
for (int i = 0; i < collector.getErrorCount(); ++i) {
result.registerError(convertMessage(collector.getError(i)));
}
}
// Register all collected warnings from the Groovy compiler
ErrorCollector collector = compilationUnit.getErrorCollector();
for (int i = 0; i < collector.getWarningCount(); ++i) {
result.registerWarning(convertMessage(collector.getWarning(i)));
}
return result;
}
// ------------------------------------------ Utility methods
/**
* <p>Converts the given Groovy compiler message into a compilation message that
* our compilation API consists of.</p>
*
* @param message the Groovy compiler message you want to convert
* @return the final converted compilation message
*/
protected CompilationResult.CompilationMessage convertMessage(Message message) {
if (message instanceof SimpleMessage) {
SimpleMessage simpleMessage = (SimpleMessage) message;
return new CompilationResult.CompilationMessage(-1, simpleMessage.getMessage());
} else if (message instanceof SyntaxErrorMessage) {
SyntaxErrorMessage syntaxErrorMessage = (SyntaxErrorMessage) message;
return new CompilationResult.CompilationMessage(
syntaxErrorMessage.getCause().getLine(), syntaxErrorMessage.getCause().getMessage());
} else {
if (logger.isDebugEnabled()) {
logger.debug(
"This compiler came across an unknown message kind ['" + message + "']. It will be ignored.");
}
return null;
}
}
/**
* <p>Configures the compiler by building its configuration object.</p>
*
* @param sourcePath the path to the source directory
* @param targetPath the path to the target directory
* @param classLoader the class loader to use to determine the classpath
* @return the compiler configuration
*/
protected CompilerConfiguration buildCompilerConfiguration(File sourcePath, File targetPath, ClassLoader classLoader) {
CompilerConfiguration configuration = new CompilerConfiguration();
// Set the destination / target directory for the compiled .class files.
configuration.setTargetDirectory(targetPath.getAbsoluteFile());
// Specify the classpath of the given class loader. This enables the user to write new Java
// "scripts" that depend on classes that have already been loaded previously. Otherwise he
// wouldn't be able to use for example classes that are available in a library.
configuration.setClasspath(ClassLoaderUtils.buildClasspath(classLoader));
// Enable verbose output.
configuration.setVerbose(true);
// Generate debugging information.
configuration.setDebug(true);
return configuration;
}
}