Move commons compiler to bundles
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1594135 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..b76d37e
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,27 @@
+Apache Sling Commons Java Compiler
+
+The Sling Commons Java Compiler bundle provides platform independant Java Compilation
+support using the Eclipse Java Compiler (org.eclipse.jdt).
+
+Getting Started
+===============
+
+This component uses a Maven 2 (http://maven.apache.org/) build
+environment. It requires a Java 5 JDK (or higher) and Maven (http://maven.apache.org/)
+2.0.7 or later. We recommend to use the latest Maven version.
+
+If you have Maven 2 installed, you can compile and
+package the jar using the following command:
+
+ mvn package
+
+See the Maven 2 documentation for other build features.
+
+The latest source code for this component is available in the
+Subversion (http://subversion.tigris.org/) source repository of
+the Apache Software Foundation. If you have Subversion installed,
+you can checkout the latest source using the following command:
+
+ svn checkout http://svn.apache.org/repos/asf/sling/trunk/contrib/commons/compiler
+
+See the Subversion documentation for other source control features.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..7638c28
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>19</version>
+ <relativePath>../../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.sling.commons.compiler</artifactId>
+ <version>2.1.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>Apache Sling Commons Java Compiler</name>
+ <description>
+ The Sling Commons Java Compiler bundle provides platform independant Java Compilation
+ support using the Eclipse Java Compiler (org.eclipse.jdt).
+ </description>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/commons/compiler</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/commons/compiler</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/contrib/commons/compiler</url>
+ </scm>
+
+ <properties>
+ <sling.java.version>6</sling.java.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ !org.eclipse.*,
+ !org.apache.tools.*,*
+ </Import-Package>
+ <Export-Package>
+ org.apache.sling.commons.compiler;version=2.1.0
+ </Export-Package>
+ <Private-Package>
+ org.apache.sling.commons.compiler.impl
+ </Private-Package>
+ <Embed-Dependency>
+ ecj
+ </Embed-Dependency>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>
+ org.apache.sling.commons.compiler.impl
+ </excludePackageNames>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.classloader</artifactId>
+ <version>1.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jdt.core.compiler</groupId>
+ <artifactId>ecj</artifactId>
+ <version>P20140317-1600</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <!-- testing -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/commons/compiler/CompilationResult.java b/src/main/java/org/apache/sling/commons/compiler/CompilationResult.java
new file mode 100644
index 0000000..4a72cbd
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/CompilationResult.java
@@ -0,0 +1,64 @@
+/*
+ * 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.sling.commons.compiler;
+
+import java.util.List;
+
+/**
+ * The compilation result allows clients of the java compiler
+ * to check for error messages, warnings (if not disabled by
+ * the options) and allows to access the compiled classes.
+ * @since 2.0
+ */
+public interface CompilationResult {
+
+ /**
+ * Return a list of error messages that occured during
+ * compilation. If no errors occured <code>null</code>
+ * is returned.
+ * @return A list of error messages or <code>null</code>.
+ */
+ List<CompilerMessage> getErrors();
+
+ /**
+ * Return a list of warnings that occured during
+ * compilation. If no warnings occured <code>null</code>
+ * is returned.
+ * @return A list of warnings or <code>null</code>.
+ */
+ List<CompilerMessage> getWarnings();
+
+ /**
+ * Was a compilation required or were all classes recent?
+ * @return <code>true>/code> if classes were compiled.
+ */
+ boolean didCompile();
+
+ /**
+ * Try to load the compiled class.
+ * The class loading might fail if the className is not
+ * one of the compiled sources, if the compilation failed
+ * or if a class loader writer has been used in combination
+ * with a class loader that is not able to load the classes
+ * written by the class loader writer.
+ * @return The compiled class
+ * @throws ClassNotFoundException If the class could not be found
+ * or compilation failed.
+ */
+ Class<?> loadCompiledClass(final String className)
+ throws ClassNotFoundException;
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/CompilationUnit.java b/src/main/java/org/apache/sling/commons/compiler/CompilationUnit.java
new file mode 100644
index 0000000..415c237
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/CompilationUnit.java
@@ -0,0 +1,48 @@
+/*
+ * 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.sling.commons.compiler;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This interface describes a compilation unit - usually a java class.
+ * @since 2.0
+ */
+public interface CompilationUnit {
+
+ /**
+ * Return an input stream for the contents.
+ * The compiler will close this stream in all cases!
+ */
+ Reader getSource()
+ throws IOException;
+
+ /**
+ * Returns the name of the top level public type.
+ * This name includes the package.
+ * @return the name of the top level public type.
+ */
+ String getMainClassName();
+
+ /**
+ * Return the last modified for the compilation unit.
+ * @return The last modified information or <code>-1</code> if
+ * the information can't be detected.
+ */
+ long getLastModified();
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/CompilationUnitWithSource.java b/src/main/java/org/apache/sling/commons/compiler/CompilationUnitWithSource.java
new file mode 100644
index 0000000..9a4921b
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/CompilationUnitWithSource.java
@@ -0,0 +1,27 @@
+/*
+ * 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.sling.commons.compiler;
+
+/**
+ * Extension of the CompilationUnit interface which allows for the explicit
+ * declaration of the source file name.
+ * @since 2.1
+ */
+public interface CompilationUnitWithSource extends CompilationUnit {
+
+ String getFileName();
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/CompilerMessage.java b/src/main/java/org/apache/sling/commons/compiler/CompilerMessage.java
new file mode 100644
index 0000000..fd98d7a
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/CompilerMessage.java
@@ -0,0 +1,101 @@
+/*
+ * 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.sling.commons.compiler;
+
+/**
+ * This class encapsulates a message produced the compiler.
+ * A message is either a warning or an error.
+ * The messages are retrieved from the {@link CompilationResult}.
+ *
+ * @since 2.0
+ */
+public class CompilerMessage {
+
+ /**
+ * The line number of the offending program text
+ */
+ private final int line;
+
+ /**
+ * The column number of the offending program text
+ */
+ private final int column;
+
+ /**
+ * The name of the file containing the offending program text
+ */
+ private final String file;
+
+ /**
+ * The actual text
+ */
+ private final String message;
+
+ /**
+ * The error message constructor.
+ *
+ * @param file The name of the file containing the offending program text
+ * @param line The line number of the offending program text
+ * @param column The column number of the offending program text
+ * @param message The actual text
+ */
+ public CompilerMessage(final String file,
+ final int line,
+ final int column,
+ final String message) {
+ this.file = file;
+ this.line = line;
+ this.column = column;
+ this.message = message;
+ }
+
+ /**
+ * Return the filename associated with this compiler message.
+ *
+ * @return The filename associated with this compiler message
+ */
+ public String getFile() {
+ return file;
+ }
+
+ /**
+ * Return the line number of the program text originating this message
+ *
+ * @return The line number of the program text originating this message
+ */
+ public int getLine() {
+ return this.line;
+ }
+
+ /**
+ * Return the column number of the program text originating this message
+ *
+ * @return The column number of the program text originating this message
+ */
+ public int getColumn() {
+ return this.column;
+ }
+
+ /**
+ * Return the message
+ *
+ * @return The message
+ */
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java b/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java
new file mode 100644
index 0000000..8d2d629
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java
@@ -0,0 +1,40 @@
+/*
+ * 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.sling.commons.compiler;
+
+/**
+ * The <code>JavaCompiler</code> provides platform independant Java
+ * compilation support.
+ */
+public interface JavaCompiler {
+
+ /**
+ * Compile the compilation units.
+ * This method checks if the compilation is necessary by using
+ * last modified check of the source to compile and the class
+ * file (if available).
+ * The compiler compiles all sources if at least one of the
+ * class files is out dated!
+ *
+ * @param units The compilation units.
+ * @param options The compilation options - this object is optional
+ * @return The compilation result with more information.
+ * @since 2.0
+ */
+ CompilationResult compile(CompilationUnit[] units,
+ Options options);
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/Options.java b/src/main/java/org/apache/sling/commons/compiler/Options.java
new file mode 100644
index 0000000..302c8c2
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/Options.java
@@ -0,0 +1,111 @@
+/*
+ * 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.sling.commons.compiler;
+
+import java.util.HashMap;
+
+/**
+ * Options for the compilation process.
+ */
+public class Options extends HashMap<String, Object> {
+
+ private static final long serialVersionUID = 1576005888428747431L;
+
+ /** The key for the source version. */
+ public static final String KEY_SOURCE_VERSION = "sourceVersion";
+
+ /** The key for the target version. */
+ public static final String KEY_TARGET_VERSION = "targetVersion";
+
+ /** The key for the generate debug info flag. */
+ public static final String KEY_GENERATE_DEBUG_INFO = "generateDebugInfo";
+
+ public static final String VERSION_RUNTIME = null;
+ public static final String VERSION_1_1 = "1.1";
+ public static final String VERSION_1_2 = "1.2";
+ public static final String VERSION_1_3 = "1.3";
+ public static final String VERSION_1_4 = "1.4";
+ public static final String VERSION_1_5 = "1.5";
+ public static final String VERSION_1_6 = "1.6";
+ public static final String VERSION_1_7 = "1.7";
+ public static final String VERSION_1_8 = "1.8";
+
+ /** The key for the class loader writer.
+ * By default the registered class loader writer service is used. */
+ public static final String KEY_CLASS_LOADER_WRITER = "classLoaderWriter";
+
+ /**
+ * The key for the class loader.
+ * By default the commons dynamic classloader is used.
+ * This property overrides the classloader and ignores the
+ * {@link #KEY_ADDITIONAL_CLASS_LOADER} completly!
+ */
+ public static final String KEY_CLASS_LOADER = "classLoader";
+
+ /**
+ * The key for the additional class loader.
+ * By default the commons dynamic classloader is used.
+ * If this property is used and the {@link #KEY_CLASS_LOADER}
+ * property is not defined, a classloader with the dynamic
+ * class loader (default) and the class loader specified here
+ * is used.
+ */
+ public static final String KEY_ADDITIONAL_CLASS_LOADER = "classLoader";
+
+ /** The key to force the compilation - even if the class files are more recent.
+ * The value should be of type Boolean. */
+ public static final String KEY_FORCE_COMPILATION = "forceCompilation";
+
+ /** The key to ignore warnings - if this option is turned on, the
+ * resulting compilation result does not get the warnings issued
+ * by the compiler.
+ * The value should be of type Boolean. */
+ public static final String KEY_IGNORE_WARNINGS = "ignoreWarnings";
+
+ /**
+ * Default options with the following presets:
+ * - generate debug info : true
+ */
+ public Options() {
+ this.put(KEY_GENERATE_DEBUG_INFO, true);
+ }
+
+ /**
+ * Create a new options object based on an existing one.
+ */
+ public Options(final Options options) {
+ super(options);
+ }
+
+ public String getSourceVersion() {
+ return (String) this.get(KEY_SOURCE_VERSION);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public String getTargetVersion() {
+ return (String) this.get(KEY_TARGET_VERSION);
+ }
+
+ public boolean isGenerateDebugInfo() {
+ if ( this.get(KEY_GENERATE_DEBUG_INFO) != null ) {
+ return (Boolean) this.get(KEY_GENERATE_DEBUG_INFO);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/impl/CompilationResultImpl.java b/src/main/java/org/apache/sling/commons/compiler/impl/CompilationResultImpl.java
new file mode 100644
index 0000000..5d878b2
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/impl/CompilationResultImpl.java
@@ -0,0 +1,114 @@
+/*
+ * 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.sling.commons.compiler.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.commons.classloader.ClassLoaderWriter;
+import org.apache.sling.commons.compiler.CompilationResult;
+import org.apache.sling.commons.compiler.CompilerMessage;
+
+/**
+ * Implementation of the compilation result
+ */
+public class CompilationResultImpl implements CompilationResult {
+
+ private List<CompilerMessage> errors;
+
+ private List<CompilerMessage> warnings;
+
+ private final boolean ignoreWarnings;
+
+ private final boolean compilationRequired;
+
+ private final ClassLoaderWriter classLoaderWriter;
+
+ public CompilationResultImpl(final String errorMessage) {
+ this.ignoreWarnings = true;
+ this.classLoaderWriter = null;
+ this.compilationRequired = false;
+ this.onError(errorMessage, "<General>", 0, 0);
+ }
+
+ public CompilationResultImpl(final ClassLoaderWriter writer) {
+ this.ignoreWarnings = true;
+ this.classLoaderWriter = writer;
+ this.compilationRequired = false;
+ }
+
+ public CompilationResultImpl(final boolean ignoreWarnings,
+ final ClassLoaderWriter writer) {
+ this.ignoreWarnings = ignoreWarnings;
+ this.classLoaderWriter = writer;
+ this.compilationRequired = true;
+ }
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationResult#getErrors()
+ */
+ public List<CompilerMessage> getErrors() {
+ return this.errors;
+ }
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationResult#getWarnings()
+ */
+ public List<CompilerMessage> getWarnings() {
+ return this.warnings;
+ }
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationResult#loadCompiledClass(java.lang.String)
+ */
+ public Class<?> loadCompiledClass(final String className)
+ throws ClassNotFoundException {
+ if ( errors != null ) {
+ throw new ClassNotFoundException(className);
+ }
+ return this.classLoaderWriter.getClassLoader().loadClass(className);
+ }
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationResult#didCompile()
+ */
+ public boolean didCompile() {
+ return this.compilationRequired;
+ }
+
+ /**
+ * Notification of an error
+ */
+ public void onError(String msg, String sourceFile, int line, int position) {
+ if ( errors == null ) {
+ errors = new ArrayList<CompilerMessage>();
+ }
+ errors.add(new CompilerMessage(sourceFile, line, position, msg));
+ }
+
+ /**
+ * Notification of a warning
+ */
+ public void onWarning(String msg, String sourceFile, int line, int position) {
+ if ( !this.ignoreWarnings ) {
+ if ( warnings == null ) {
+ warnings = new ArrayList<CompilerMessage>();
+ }
+ warnings.add(new CompilerMessage(sourceFile, line, position, msg));
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java b/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java
new file mode 100644
index 0000000..b969f26
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java
@@ -0,0 +1,479 @@
+/*
+ * 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.sling.commons.compiler.impl;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.classloader.ClassLoaderWriter;
+import org.apache.sling.commons.compiler.CompilationResult;
+import org.apache.sling.commons.compiler.CompilationUnit;
+import org.apache.sling.commons.compiler.CompilationUnitWithSource;
+import org.apache.sling.commons.compiler.JavaCompiler;
+import org.apache.sling.commons.compiler.Options;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
+import org.eclipse.jdt.internal.compiler.IProblemFactory;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>EclipseJavaCompiler</code> provides platform independant
+ * Java compilation support using the Eclipse Java Compiler (org.eclipse.jdt).
+ *
+ */
+@Component
+@Service(value=JavaCompiler.class)
+public class EclipseJavaCompiler implements JavaCompiler {
+
+ /** Logger instance */
+ private final Logger logger = LoggerFactory.getLogger(EclipseJavaCompiler.class);
+
+ @Reference
+ private ClassLoaderWriter classLoaderWriter;
+
+ /** the static problem factory */
+ private IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
+
+ /** the static policy. */
+ private final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems();
+
+ /**
+ * Get the classloader for the compilation.
+ */
+ private ClassLoader getClassLoader(final Options options, final ClassLoaderWriter classLoaderWriter) {
+ final ClassLoader loader;
+ if ( options.get(Options.KEY_CLASS_LOADER) != null ) {
+ loader = (ClassLoader)options.get(Options.KEY_CLASS_LOADER);
+ } else if ( options.get(Options.KEY_ADDITIONAL_CLASS_LOADER) != null ) {
+ final ClassLoader additionalClassLoader = (ClassLoader)options.get(Options.KEY_ADDITIONAL_CLASS_LOADER);
+ loader = new ClassLoader(classLoaderWriter.getClassLoader()) {
+ @Override
+ protected Class<?> findClass(String name)
+ throws ClassNotFoundException {
+ return additionalClassLoader.loadClass(name);
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ return additionalClassLoader.getResource(name);
+ }
+ };
+ } else {
+ final ClassLoader cl = classLoaderWriter.getClassLoader();
+ if ( cl == null ) {
+ loader = this.classLoaderWriter.getClassLoader();
+ } else {
+ loader = cl;
+ }
+ }
+ return loader;
+ }
+
+ /**
+ * Get the class loader writer for the compilation.
+ */
+ private ClassLoaderWriter getClassLoaderWriter(final Options options) {
+ if (options.get(Options.KEY_CLASS_LOADER_WRITER) != null ) {
+ return (ClassLoaderWriter)options.get(Options.KEY_CLASS_LOADER_WRITER);
+ }
+ return this.classLoaderWriter;
+ }
+
+ /**
+ * Check if the compiled class file is older than the source file
+ */
+ private boolean isOutDated(final CompilationUnit unit,
+ final ClassLoaderWriter writer) {
+ final long targetLastModified = writer.getLastModified('/' + unit.getMainClassName().replace('.', '/') + ".class");
+ if (targetLastModified < 0) {
+ return true;
+ }
+
+ return targetLastModified < unit.getLastModified();
+ }
+
+ /**
+ * Return the force compilation value
+ */
+ private boolean isForceCompilation(final Options options) {
+ final Boolean flag = (Boolean)options.get(Options.KEY_FORCE_COMPILATION);
+ if ( flag != null ) {
+ return flag;
+ }
+ return false;
+ }
+
+ /**
+ * Return the ignore warnings value
+ */
+ private boolean isIgnoreWarnings(final Options options) {
+ final Boolean flag = (Boolean)options.get(Options.KEY_IGNORE_WARNINGS);
+ if ( flag != null ) {
+ return flag;
+ }
+ return false;
+ }
+
+ private static final Options EMPTY_OPTIONS = new Options();
+
+ /**
+ * @see org.apache.sling.commons.compiler.JavaCompiler#compile(org.apache.sling.commons.compiler.CompilationUnit[], org.apache.sling.commons.compiler.Options)
+ */
+ public CompilationResult compile(final CompilationUnit[] units,
+ final Options compileOptions) {
+ // make sure we have an options object (to avoid null checks all over the place)
+ final Options options = (compileOptions != null ? compileOptions : EMPTY_OPTIONS);
+
+ // get classloader and classloader writer
+ final ClassLoaderWriter writer = this.getClassLoaderWriter(options);
+ if ( writer == null ) {
+ return new CompilationResultImpl("Class loader writer for compilation is not available.");
+ }
+ final ClassLoader loader = this.getClassLoader(options, writer);
+ if ( loader == null ) {
+ return new CompilationResultImpl("Class loader for compilation is not available.");
+ }
+
+ // check sources for compilation
+ boolean needsCompilation = isForceCompilation(options);
+ if ( !needsCompilation ) {
+ for(final CompilationUnit unit : units) {
+ if ( this.isOutDated(unit, writer) ) {
+ needsCompilation = true;
+ break;
+ }
+ }
+ }
+ if ( !needsCompilation ) {
+ logger.debug("All source files are recent - no compilation required.");
+ return new CompilationResultImpl(writer);
+ }
+
+ // delete old class files
+ for(final CompilationUnit unit : units) {
+ final String name = '/' + unit.getMainClassName().replace('.', '/') + ".class";
+ writer.delete(name);
+ }
+
+ // create properties for the settings object
+ final Map<String, String> props = new HashMap<String, String>();
+ if (options.isGenerateDebugInfo()) {
+ props.put(CompilerOptions.OPTION_LocalVariableAttribute, "generate");
+ props.put(CompilerOptions.OPTION_LineNumberAttribute, "generate");
+ props.put(CompilerOptions.OPTION_SourceFileAttribute, "generate");
+ }
+ if (options.getSourceVersion() != null) {
+ props.put(CompilerOptions.OPTION_Source, options.getSourceVersion());
+ props.put(CompilerOptions.OPTION_Compliance, options.getSourceVersion());
+ }
+ if (options.getTargetVersion() != null) {
+ props.put(CompilerOptions.OPTION_TargetPlatform, options.getTargetVersion());
+ }
+ props.put(CompilerOptions.OPTION_Encoding, "UTF8");
+
+ // create the settings
+ final CompilerOptions settings = new CompilerOptions(props);
+ logger.debug("Compiling with settings {}.", settings);
+
+ // create the result
+ final CompilationResultImpl result = new CompilationResultImpl(isIgnoreWarnings(options), writer);
+ // create the context
+ final CompileContext context = new CompileContext(units, result, writer, loader);
+
+ // create the compiler
+ final org.eclipse.jdt.internal.compiler.Compiler compiler =
+ new org.eclipse.jdt.internal.compiler.Compiler(
+ context,
+ this.policy,
+ settings,
+ context,
+ this.problemFactory,
+ null,
+ null);
+
+ // compile
+ compiler.compile(context.getSourceUnits());
+
+ return result;
+ }
+
+ //--------------------------------------------------------< inner classes >
+
+ private class CompileContext implements ICompilerRequestor, INameEnvironment {
+
+ private final Map<String,ICompilationUnit> compUnits;
+
+ private final CompilationResultImpl errorHandler;
+ private final ClassLoaderWriter classLoaderWriter;
+ private final ClassLoader classLoader;
+
+ public CompileContext(final CompilationUnit[] units,
+ final CompilationResultImpl errorHandler,
+ final ClassLoaderWriter classWriter,
+ final ClassLoader classLoader) {
+ this.compUnits = new HashMap<String,ICompilationUnit>();
+ for (int i = 0; i < units.length; i++) {
+ CompilationUnitAdapter cua = new CompilationUnitAdapter(units[i], errorHandler);
+ char[][] compoundName = CharOperation.arrayConcat(cua.getPackageName(), cua.getMainTypeName());
+ this.compUnits.put(CharOperation.toString(compoundName), new CompilationUnitAdapter(units[i], errorHandler));
+ }
+
+ this.errorHandler = errorHandler;
+ this.classLoaderWriter = classWriter;
+ this.classLoader = classLoader;
+ }
+
+ public ICompilationUnit[] getSourceUnits() {
+ return compUnits.values().toArray(
+ new ICompilationUnit[compUnits.size()]);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.ICompilerRequestor#acceptResult(org.eclipse.jdt.internal.compiler.CompilationResult)
+ */
+ public void acceptResult(org.eclipse.jdt.internal.compiler.CompilationResult result) {
+ if (result.hasProblems()) {
+ CategorizedProblem[] problems = result.getProblems();
+ for (int i = 0; i < problems.length; i++) {
+ CategorizedProblem problem = problems[i];
+ String msg = problem.getMessage();
+ String fileName = CharOperation.charToString(problem.getOriginatingFileName());
+ int line = problem.getSourceLineNumber();
+ int pos = problem.getSourceStart();
+
+ if (problem.isError()) {
+ this.errorHandler.onError(msg, fileName, line, pos);
+ } else if (problem.isWarning()) {
+ this.errorHandler.onWarning(msg, fileName, line, pos);
+ } else {
+ logger.debug("unknown problem category: {}", problem);
+ }
+ }
+ }
+ ClassFile[] classFiles = result.getClassFiles();
+ for (int i = 0; i < classFiles.length; i++) {
+ ClassFile classFile = classFiles[i];
+ String className = CharOperation.toString(classFile.getCompoundName());
+ try {
+ this.write(className, classFile.getBytes());
+ } catch (IOException e) {
+ this.errorHandler.onError("Unable to write class file: " + e.getMessage(), className, 0, 0);
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[][])
+ */
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ // check 1st if type corresponds with any of current compilation units
+ String fqn = CharOperation.toString(compoundTypeName);
+ ICompilationUnit cu = compUnits.get(fqn);
+ if (cu != null) {
+ return new NameEnvironmentAnswer(cu, null);
+ }
+
+ // locate the class through the class loader
+ try {
+ byte[] bytes = this.findClass(CharOperation.toString(compoundTypeName));
+ if (bytes == null) {
+ return null;
+ }
+ ClassFileReader classFileReader =
+ new ClassFileReader(bytes, fqn.toCharArray(), true);
+ return new NameEnvironmentAnswer(classFileReader, null);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[], char[][])
+ */
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+ return findType(CharOperation.arrayConcat(packageName, typeName));
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#isPackage(char[][], char[])
+ */
+ public boolean isPackage(char[][] parentPackageName, char[] packageName) {
+ String fqn = CharOperation.toString(
+ CharOperation.arrayConcat(parentPackageName, packageName));
+ return compUnits.get(fqn) == null && this.isPackage(fqn);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#cleanup()
+ */
+ public void cleanup() {
+ // nothing to do
+ }
+
+ /**
+ * Write the classfile
+ */
+ private void write(String name, byte[] data) throws IOException {
+ final OutputStream os = this.classLoaderWriter.getOutputStream('/' + name.replace('.', '/') + ".class");
+ os.write(data);
+ os.close();
+ }
+
+ private boolean isPackage(String result) {
+ String resourceName = result.replace('.', '/') + ".class";
+ if ( resourceName.startsWith("/") ) {
+ resourceName = resourceName.substring(1);
+ }
+ final InputStream is = this.classLoader.getResourceAsStream(resourceName);
+ if ( is != null ) {
+ try {
+ is.close();
+ } catch (IOException ignore) {}
+ }
+ return is == null;
+ }
+
+ private byte[] findClass(String name) throws Exception {
+ final String resourceName = name.replace('.', '/') + ".class";
+ final InputStream is = this.classLoader.getResourceAsStream(resourceName);
+ if (is != null) {
+ try {
+ byte[] buf = new byte[8192];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(buf.length);
+ int count;
+ while ((count = is.read(buf, 0, buf.length)) > 0) {
+ baos.write(buf, 0, count);
+ }
+ baos.flush();
+ return baos.toByteArray();
+ } finally {
+ try {
+ is.close();
+ } catch (IOException ignore) {}
+ }
+ }
+ return null;
+ }
+ }
+
+ private class CompilationUnitAdapter implements ICompilationUnit {
+
+ private final CompilationResultImpl errorHandler;
+ private final CompilationUnit compUnit;
+ private final String mainTypeName;
+ private final String packageName;
+
+ public CompilationUnitAdapter(final CompilationUnit compUnit, final CompilationResultImpl errorHandler) {
+ this.compUnit = compUnit;
+ this.errorHandler = errorHandler;
+ final int pos = compUnit.getMainClassName().lastIndexOf('.');
+ if ( pos == -1 ) {
+ this.packageName = "";
+ this.mainTypeName = compUnit.getMainClassName();
+ } else {
+ this.packageName = compUnit.getMainClassName().substring(0, pos);
+ this.mainTypeName = compUnit.getMainClassName().substring(pos + 1);
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents()
+ */
+ public char[] getContents() {
+ Reader fr = null;
+ try {
+ fr = this.compUnit.getSource();
+ final Reader reader = new BufferedReader(fr);
+ try {
+ char[] chars = new char[8192];
+ StringBuilder buf = new StringBuilder();
+ int count;
+ while ((count = reader.read(chars, 0, chars.length)) > 0) {
+ buf.append(chars, 0, count);
+ }
+ final char[] result = new char[buf.length()];
+ buf.getChars(0, result.length, result, 0);
+ return result;
+ } finally {
+ reader.close();
+ }
+ } catch (IOException e) {
+ this.errorHandler.onError("Unable to read source file " + this.compUnit.getMainClassName() + " : " + e.getMessage(),
+ this.compUnit.getMainClassName(), 0, 0);
+ return null;
+ } finally {
+ if ( fr != null ) {
+ try { fr.close(); } catch (IOException ignore) {}
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getMainTypeName()
+ */
+ public char[] getMainTypeName() {
+ return this.mainTypeName.toCharArray();
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getPackageName()
+ */
+ public char[][] getPackageName() {
+ return CharOperation.splitOn('.', this.packageName.toCharArray());
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName()
+ */
+ public char[] getFileName() {
+ if (compUnit instanceof CompilationUnitWithSource) {
+ return ((CompilationUnitWithSource)compUnit).getFileName().toCharArray();
+ } else {
+ return (this.packageName.replace('.', '/') + '/' + this.mainTypeName + ".java").toCharArray();
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#ignoreOptionalProblems()
+ */
+ public boolean ignoreOptionalProblems() {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/commons/compiler/impl/IsolatedClassLoader.java b/src/main/java/org/apache/sling/commons/compiler/impl/IsolatedClassLoader.java
new file mode 100644
index 0000000..ace970a
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/compiler/impl/IsolatedClassLoader.java
@@ -0,0 +1,162 @@
+/*
+ * 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.sling.commons.compiler.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+
+import org.apache.sling.commons.classloader.ClassLoaderWriter;
+
+
+/**
+ * The <code>IsolatedClassLoader</code> class loads classes through
+ * the class loader writer
+ */
+public final class IsolatedClassLoader
+ extends SecureClassLoader {
+
+ private final ClassLoaderWriter classLoaderWriter;
+
+ public IsolatedClassLoader(final ClassLoader parent,
+ final ClassLoaderWriter classLoaderWriter) {
+ super(parent);
+ this.classLoaderWriter = classLoaderWriter;
+ }
+
+
+ //---------- Class loader overwrites -------------------------------------
+
+ /**
+ * Loads the class from this <code>ClassLoader</class>. If the
+ * class does not exist in this one, we check the parent. Please
+ * note that this is the exact opposite of the
+ * <code>ClassLoader</code> spec. We use it to work around
+ * inconsistent class loaders from third party vendors.
+ *
+ * @param name the name of the class
+ * @param resolve if <code>true</code> then resolve the class
+ * @return the resulting <code>Class</code> object
+ * @exception ClassNotFoundException if the class could not be found
+ */
+ public final Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ // First check if it's already loaded
+ Class<?> clazz = findLoadedClass(name);
+
+ if (clazz == null) {
+
+ try {
+ clazz = findClass(name);
+ } catch (final ClassNotFoundException cnfe) {
+ final ClassLoader parent = getParent();
+ if (parent != null) {
+ // Ask to parent ClassLoader (can also throw a CNFE).
+ clazz = parent.loadClass(name);
+ } else {
+ // Propagate exception
+ throw cnfe;
+ }
+ }
+ }
+
+ if (resolve) {
+ resolveClass(clazz);
+ }
+
+ return clazz;
+ }
+
+ /**
+ * Finds and loads the class with the specified name from the class path.
+ *
+ * @param name the name of the class
+ * @return the resulting class
+ *
+ * @throws ClassNotFoundException If the named class could not be found or
+ * if this class loader has already been destroyed.
+ */
+ protected Class<?> findClass(final String name) throws ClassNotFoundException {
+ try {
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Class<?>>() {
+
+ public Class<?> run() throws ClassNotFoundException {
+ return findClassPrivileged(name);
+ }
+ });
+ } catch (final java.security.PrivilegedActionException pae) {
+ throw (ClassNotFoundException) pae.getException();
+ }
+ }
+
+ /**
+ * Tries to find the class in the class path from within a
+ * <code>PrivilegedAction</code>. Throws <code>ClassNotFoundException</code>
+ * if no class can be found for the name.
+ *
+ * @param name the name of the class
+ *
+ * @return the resulting class
+ *
+ * @throws ClassNotFoundException if the class could not be found
+ * @throws NullPointerException If this class loader has already been
+ * destroyed.
+ */
+ private Class<?> findClassPrivileged(final String name) throws ClassNotFoundException {
+ // prepare the name of the class
+ final String path = "/" + name.replace('.', '/') + ".class";
+ InputStream is = null;
+ try {
+ is = this.classLoaderWriter.getInputStream(path);
+ final Class<?> c = defineClass(name, is);
+ if (c == null) {
+ throw new ClassNotFoundException(name);
+ }
+ return c;
+ } catch ( final ClassNotFoundException cnfe) {
+ throw cnfe;
+ } catch (final Throwable t) {
+ throw new ClassNotFoundException(name, t);
+ }
+ }
+
+ /**
+ * Defines a class getting the bytes for the class from the resource
+ *
+ * @param name The fully qualified class name
+ * @param is The resource to obtain the class bytes from
+ *
+ * @throws IOException If a problem occurrs reading the class bytes from
+ * the resource.
+ * @throws ClassFormatError If the class bytes read from the resource are
+ * not a valid class.
+ */
+ private Class<?> defineClass(final String name, final InputStream is)
+ throws IOException {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final byte[] buffer = new byte[2048];
+ int l;
+ while ( ( l = is.read(buffer)) >= 0 ) {
+ baos.write(buffer, 0, l);
+ }
+ final byte[] data = baos.toByteArray();
+ return defineClass(name, data, 0, data.length);
+ }
+}
diff --git a/src/test/java/org/apache/sling/commons/compiler/impl/CompilerJava5Test.java b/src/test/java/org/apache/sling/commons/compiler/impl/CompilerJava5Test.java
new file mode 100644
index 0000000..ac5f0b5
--- /dev/null
+++ b/src/test/java/org/apache/sling/commons/compiler/impl/CompilerJava5Test.java
@@ -0,0 +1,123 @@
+/*
+ * 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.sling.commons.compiler.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+
+import junit.framework.TestCase;
+
+import org.apache.sling.commons.classloader.ClassLoaderWriter;
+import org.apache.sling.commons.compiler.CompilationResult;
+import org.apache.sling.commons.compiler.CompilationUnit;
+import org.apache.sling.commons.compiler.Options;
+
+/**
+ * Test case for java 5 support
+ */
+public class CompilerJava5Test extends TestCase
+ implements ClassLoaderWriter {
+
+ public void testJava5Support() throws Exception {
+ String sourceFile = "Java5Test";
+
+ CompilationUnit unit = createCompileUnit(sourceFile);
+ final Options options = new Options();
+ options.put(Options.KEY_SOURCE_VERSION, Options.VERSION_1_5);
+ options.put(Options.KEY_CLASS_LOADER_WRITER, this);
+ options.put(Options.KEY_CLASS_LOADER, this.getClass().getClassLoader());
+
+ final CompilationResult result = new EclipseJavaCompiler().compile(new CompilationUnit[]{unit}, options);
+ assertNotNull(result);
+ assertNull(result.getErrors());
+ }
+
+ //--------------------------------------------------------< misc. helpers >
+
+ private CompilationUnit createCompileUnit(final String sourceFile) throws Exception {
+ return new CompilationUnit() {
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationUnit#getMainClassName()
+ */
+ public String getMainClassName() {
+ return "org.apache.sling.commons.compiler.test." + sourceFile;
+ }
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationUnit#getSource()
+ */
+ public Reader getSource() throws IOException {
+ InputStream in = getClass().getClassLoader().getResourceAsStream(sourceFile);
+ return new InputStreamReader(in, "UTF-8");
+ }
+
+ /**
+ * @see org.apache.sling.commons.compiler.CompilationUnit#getLastModified()
+ */
+ public long getLastModified() {
+ return 0;
+ }
+ };
+ }
+
+ /**
+ * @see org.apache.sling.commons.classloader.ClassLoaderWriter#delete(java.lang.String)
+ */
+ public boolean delete(String path) {
+ return false;
+ }
+
+ /**
+ * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getInputStream(java.lang.String)
+ */
+ public InputStream getInputStream(String path) throws IOException {
+ return null;
+ }
+
+ /**
+ * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getLastModified(java.lang.String)
+ */
+ public long getLastModified(String path) {
+ return -1;
+ }
+
+ /**
+ * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getOutputStream(java.lang.String)
+ */
+ public OutputStream getOutputStream(String path) {
+ return new ByteArrayOutputStream();
+ }
+
+ /**
+ * @see org.apache.sling.commons.classloader.ClassLoaderWriter#rename(java.lang.String, java.lang.String)
+ */
+ public boolean rename(String oldPath, String newPath) {
+ return false;
+ }
+
+ /**
+ * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getClassLoader()
+ */
+ public ClassLoader getClassLoader() {
+ return null;
+ }
+}
diff --git a/src/test/resources/Java5Test b/src/test/resources/Java5Test
new file mode 100644
index 0000000..44658bc
--- /dev/null
+++ b/src/test/resources/Java5Test
@@ -0,0 +1,31 @@
+/*
+ * 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.sling.commons.compiler.test;
+
+import java.util.List;
+
+/**
+ * Class to test to compile Java 5 specific code
+ */
+public class Java5Test {
+ public int sum(List<Integer> intList) {
+ int result = 0;
+ for(int i=0;i<intList.size();i++)
+ result += intList.get(i).intValue();
+ return result;
+ }
+}