You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:20:37 UTC

[sling-org-apache-sling-commons-compiler] 05/14: SLING-1451 : Clean up compiler API and use classloading infrastructure

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.commons.compiler-2.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-commons-compiler.git

commit 64fdb9e597f9f62deadfbcea526cf20c7d81e80d
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Mar 19 14:50:41 2010 +0000

    SLING-1451 : Clean up compiler API and use classloading infrastructure
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/commons/compiler@925247 13f79535-47bb-0310-9956-ffa450edef68
---
 NOTICE                                             |   2 +-
 pom.xml                                            |  16 +-
 .../apache/sling/commons/compiler/ClassWriter.java |  31 --
 .../{CompileUnit.java => CompilationUnit.java}     |  20 +-
 .../commons/compiler/CompilerEnvironment.java      |  26 --
 .../sling/commons/compiler/ErrorHandler.java       |  22 +-
 .../sling/commons/compiler/JavaCompiler.java       |  18 +-
 .../org/apache/sling/commons/compiler/Options.java |  71 +++-
 .../commons/compiler/impl/EclipseJavaCompiler.java | 370 ++++++++++++++-------
 src/main/resources/META-INF/NOTICE                 |   2 +-
 .../commons/compiler/impl/CompilerJava5Test.java   | 146 +++-----
 src/test/resources/Java5Test                       |   2 +-
 12 files changed, 420 insertions(+), 306 deletions(-)

diff --git a/NOTICE b/NOTICE
index 3341854..76ff9f0 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
 Apache Sling Java Compiler
-Copyright 2008-2009 The Apache Software Foundation
+Copyright 2008-2010 The Apache Software Foundation
 
 Apache Sling is based on source code originally developed 
 by Day Software (http://www.day.com/).
diff --git a/pom.xml b/pom.xml
index 3c2906d..cc1b3e1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,7 +59,7 @@
                             !org.eclipse.*,*
                         </Import-Package>
                         <Export-Package>
-                            org.apache.sling.commons.compiler;version=1.0.0
+                            org.apache.sling.commons.compiler;version=2.0.0
                         </Export-Package>
                         <Private-Package>
                             org.apache.sling.commons.compiler.impl
@@ -88,6 +88,18 @@
 
     <dependencies>
         <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>1.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.classloader</artifactId>
+            <version>1.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.eclipse.jdt</groupId>
             <artifactId>core</artifactId>
             <version>3.3.0-v_771</version>
@@ -111,12 +123,10 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-simple</artifactId>
-            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/commons/compiler/ClassWriter.java b/src/main/java/org/apache/sling/commons/compiler/ClassWriter.java
deleted file mode 100644
index 46dc92a..0000000
--- a/src/main/java/org/apache/sling/commons/compiler/ClassWriter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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;
-
-/**
- *
- */
-public interface ClassWriter {
-
-    /**
-     *
-     * @param className
-     * @param data
-     * @throws Exception
-     */
-    void write(String className, byte[] data) throws Exception;
-}
diff --git a/src/main/java/org/apache/sling/commons/compiler/CompileUnit.java b/src/main/java/org/apache/sling/commons/compiler/CompilationUnit.java
similarity index 70%
rename from src/main/java/org/apache/sling/commons/compiler/CompileUnit.java
rename to src/main/java/org/apache/sling/commons/compiler/CompilationUnit.java
index 92723ca..fd060c2 100644
--- a/src/main/java/org/apache/sling/commons/compiler/CompileUnit.java
+++ b/src/main/java/org/apache/sling/commons/compiler/CompilationUnit.java
@@ -16,16 +16,26 @@
  */
 package org.apache.sling.commons.compiler;
 
-public interface CompileUnit {
+import java.io.IOException;
+import java.io.Reader;
 
-    String getSourceFileName();
+/**
+ * This interface describes a compilation unit - usually a java class.
+ * @since 2.0
+ */
+public interface CompilationUnit {
 
-    char[] getSourceFileContents();
+    /**
+     * 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 getMainTypeName();
+    String getMainClassName();
 }
diff --git a/src/main/java/org/apache/sling/commons/compiler/CompilerEnvironment.java b/src/main/java/org/apache/sling/commons/compiler/CompilerEnvironment.java
deleted file mode 100644
index cddb7f7..0000000
--- a/src/main/java/org/apache/sling/commons/compiler/CompilerEnvironment.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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;
-
-public interface CompilerEnvironment {
-
-    byte[] findClass(String className) throws Exception;
-
-    boolean isPackage(String packageName);
-
-    void cleanup();
-}
diff --git a/src/main/java/org/apache/sling/commons/compiler/ErrorHandler.java b/src/main/java/org/apache/sling/commons/compiler/ErrorHandler.java
index 40cf544..cebb678 100644
--- a/src/main/java/org/apache/sling/commons/compiler/ErrorHandler.java
+++ b/src/main/java/org/apache/sling/commons/compiler/ErrorHandler.java
@@ -17,25 +17,25 @@
 package org.apache.sling.commons.compiler;
 
 /**
- *
+ * The error handler for the compilation.
  */
 public interface ErrorHandler {
 
     /**
-     *
-     * @param msg
-     * @param sourceFile
-     * @param line
-     * @param position
+     * Notify the handler of an error.
+     * @param msg The error message.
+     * @param sourceFile The source file the error occured in
+     * @param line The source line number
+     * @param position The column
      */
     void onError(String msg, String sourceFile, int line, int position);
 
     /**
-     *
-     * @param msg
-     * @param sourceFile
-     * @param line
-     * @param position
+     * Notify the handler of a warning.
+     * @param msg The warning message.
+     * @param sourceFile The source file the warning occured in
+     * @param line The source line number
+     * @param position The column
      */
     void onWarning(String msg, String sourceFile, int line, int position);
 }
diff --git a/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java b/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java
index 67240f0..033b027 100644
--- a/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java
+++ b/src/main/java/org/apache/sling/commons/compiler/JavaCompiler.java
@@ -17,12 +17,20 @@
 package org.apache.sling.commons.compiler;
 
 /**
- * The <code>JavaCompiler</code> provides platform independant Java Compilation
- * support.
+ * The <code>JavaCompiler</code> provides platform independant Java
+ * compilation support.
  */
 public interface JavaCompiler {
 
-    boolean compile(CompileUnit[] units, CompilerEnvironment env,
-                        ClassWriter classWriter, ErrorHandler errorHandler,
-                        Options options);
+    /**
+     * Compile the compilation units.
+     * @param units The compilation units.
+     * @param errorHandler The error handler - this object is mandatory
+     * @param options The compilation options - this object is optional
+     * @return <code>true</code> if compilation was successful
+     * @since 2.0
+     */
+    boolean compile(CompilationUnit[] units,
+                    ErrorHandler errorHandler,
+                    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
index 23b0625..366f6f0 100644
--- a/src/main/java/org/apache/sling/commons/compiler/Options.java
+++ b/src/main/java/org/apache/sling/commons/compiler/Options.java
@@ -16,7 +16,21 @@
  */
 package org.apache.sling.commons.compiler;
 
-public class Options {
+import java.util.HashMap;
+
+/**
+ * Options for the compilation process.
+ */
+public class Options extends HashMap<String, Object> {
+
+    /** 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";
@@ -24,33 +38,54 @@ public class Options {
     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_6 = "1.6";
+    public static final String VERSION_1_7 = "1.7";
 
-    protected String sourceVersion;
-    protected boolean generateDebugInfo;
+    /** 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";
+
+    /**
+     * Default options with the following presets:
+     * - generate debug info : true
+     */
     public Options() {
-        this(VERSION_RUNTIME, true);
-    }
-    
-    public Options(String sourceVersion, boolean generateDebugInfo) {
-        this.sourceVersion = sourceVersion;
-        this.generateDebugInfo = generateDebugInfo;
+        this.put(KEY_GENERATE_DEBUG_INFO, true);
     }
 
     public String getSourceVersion() {
-        return sourceVersion;
+        return (String) this.get(KEY_SOURCE_VERSION);
     }
 
-    public void setSourceVersion(String sourceVersion) {
-        this.sourceVersion = sourceVersion;
+    /**
+     * @since 2.0
+     */
+    public String getTargetVersion() {
+        return (String) this.get(KEY_TARGET_VERSION);
     }
 
     public boolean isGenerateDebugInfo() {
-        return generateDebugInfo;
-    }
-
-    public void setGenerateDebugInfo(boolean generateDebugInfo) {
-        this.generateDebugInfo = generateDebugInfo;
+        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/EclipseJavaCompiler.java b/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java
index 8dc6c1a..bac1a1d 100644
--- a/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java
+++ b/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java
@@ -17,16 +17,22 @@
 package org.apache.sling.commons.compiler.impl;
 
 import java.io.BufferedReader;
-import java.io.CharArrayReader;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.PrintWriter;
+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.sling.commons.compiler.ClassWriter;
-import org.apache.sling.commons.compiler.CompileUnit;
-import org.apache.sling.commons.compiler.CompilerEnvironment;
+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.classloader.DynamicClassLoaderManager;
+import org.apache.sling.commons.compiler.CompilationUnit;
 import org.apache.sling.commons.compiler.ErrorHandler;
 import org.apache.sling.commons.compiler.JavaCompiler;
 import org.apache.sling.commons.compiler.Options;
@@ -48,122 +54,194 @@ 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).
+ * The <code>EclipseJavaCompiler</code> provides platform independant
+ * Java compilation support using the Eclipse Java Compiler (org.eclipse.jdt).
  *
- * @scr.component metatype="no"
- * @scr.service interface="org.apache.sling.commons.compiler.JavaCompiler"
  */
+@Component
+@Service(value=JavaCompiler.class)
 public class EclipseJavaCompiler implements JavaCompiler {
 
     /** Logger instance */
-    private static final Logger log = LoggerFactory.getLogger(EclipseJavaCompiler.class);
+    private final Logger logger = LoggerFactory.getLogger(EclipseJavaCompiler.class);
 
-    // the static problem factory
-    private static IProblemFactory PROBLEM_FACTORY =
-        new DefaultProblemFactory(Locale.getDefault());
+    @Reference
+    private ClassLoaderWriter classLoaderWriter;
 
-    public EclipseJavaCompiler() {
-    }
+    @Reference
+    private DynamicClassLoaderManager dynamicClassLoaderManager;
+
+    private ClassLoader classLoader;
+
+    /** the static problem factory */
+    private IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
+
+    /** the static policy. */
+    private final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems();
 
     /**
-     * @see org.apache.sling.commons.compiler.JavaCompiler#compile(org.apache.sling.commons.compiler.CompileUnit[], org.apache.sling.commons.compiler.CompilerEnvironment, org.apache.sling.commons.compiler.ClassWriter, org.apache.sling.commons.compiler.ErrorHandler, org.apache.sling.commons.compiler.Options)
+     * Bind the class load provider.
+     * @param repositoryClassLoaderProvider the new provider
      */
-    public boolean compile(CompileUnit[] units, CompilerEnvironment env,
-            ClassWriter classWriter, ErrorHandler errorHandler,
-            Options options) {
+    protected void bindDynamicClassLoaderManager(final DynamicClassLoaderManager rclp) {
+        if ( this.classLoader != null ) {
+            this.ungetClassLoader();
+        }
+        this.getClassLoader(rclp);
+    }
 
-        IErrorHandlingPolicy policy =
-            DefaultErrorHandlingPolicies.proceedWithAllProblems();
+    /**
+     * Unbind the class loader provider.
+     * @param repositoryClassLoaderProvider the old provider
+     */
+    protected void unbindDynamicClassLoaderManager(final DynamicClassLoaderManager rclp) {
+        if ( this.dynamicClassLoaderManager == rclp ) {
+            this.ungetClassLoader();
+        }
+    }
 
-        // output for non-error log messages
-        PrintWriter logWriter = null;
+    /**
+     * Get the class loader
+     */
+    private void getClassLoader(final DynamicClassLoaderManager rclp) {
+        this.dynamicClassLoaderManager = rclp;
+        this.classLoader = rclp.getDynamicClassLoader();
+    }
 
-        if (options == null) {
-            options = new Options();
-        }
+    /**
+     * Unget the class loader
+     */
+    private void ungetClassLoader() {
+        this.classLoader = null;
+        this.dynamicClassLoaderManager = null;
+    }
 
-        Map<String, String> props = new HashMap<String, String>();
+    /**
+     * @see org.apache.sling.commons.compiler.JavaCompiler#compile(org.apache.sling.commons.compiler.CompilationUnit[], org.apache.sling.commons.compiler.ErrorHandler, org.apache.sling.commons.compiler.Options)
+     */
+    public boolean compile(final CompilationUnit[] units,
+                           final ErrorHandler errorHandler,
+                           final Options compileOptions) {
+        // make sure we have an options object (to avoid null checks all over the place)
+        final Options options = (compileOptions != null ? compileOptions : new Options());
+
+        // create properties for the settings object
+        final Map<String, String> props = new HashMap<String, String>();
         if (options.isGenerateDebugInfo()) {
             props.put("org.eclipse.jdt.core.compiler.debug.localVariable", "generate");
             props.put("org.eclipse.jdt.core.compiler.debug.lineNumber", "generate");
             props.put("org.eclipse.jdt.core.compiler.debug.sourceFile", "generate");
         }
-        String sourceVersion = options.getSourceVersion();
-        if (sourceVersion != null) {
-            props.put("org.eclipse.jdt.core.compiler.source", sourceVersion);
-            //options.put("org.eclipse.jdt.core.compiler.compliance", sourceVersion);
-            //options.put("org.eclipse.jdt.core.compiler.codegen.targetPlatform", sourceVersion);
+        if (options.getSourceVersion() != null) {
+            props.put("org.eclipse.jdt.core.compiler.source", options.getSourceVersion());
+            //props.put("org.eclipse.jdt.core.compiler.compliance", options.getSourceVersion());
+            //props.put("org.eclipse.jdt.core.compiler.codegen.targetPlatform", options.getSourceVersion());
         }
-        //options.put("org.eclipse.jdt.core.encoding", "UTF8");
-        CompilerOptions settings = new CompilerOptions(props);
-
-        CompileContext context = new CompileContext(units, env, errorHandler, classWriter);
+        if (options.getTargetVersion() != null) {
+            props.put("org.eclipse.jdt.core.compiler.codegen.targetPlatform", options.getTargetVersion());
+        }
+        props.put("org.eclipse.jdt.core.encoding", "UTF8");
+
+        // create the settings
+        final CompilerOptions settings = new CompilerOptions(props);
+        logger.debug("Compiling with settings {}.", settings);
+
+        // classloader
+        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(this.classLoader) {
+                protected Class<?> findClass(String name)
+                throws ClassNotFoundException {
+                    return additionalClassLoader.loadClass(name);
+                }
 
-        if (log.isDebugEnabled()) {
-            log.debug(settings.toString());
+                protected URL findResource(String name) {
+                    return additionalClassLoader.getResource(name);
+                }
+            };
+        } else {
+            loader = this.classLoader;
         }
 
-        org.eclipse.jdt.internal.compiler.Compiler compiler =
+        // classloader writer
+        final ClassLoaderWriter writer = (options.get(Options.KEY_CLASS_LOADER_WRITER) != null ?
+                (ClassLoaderWriter)options.get(Options.KEY_CLASS_LOADER_WRITER) : this.classLoaderWriter);
+
+        // create the context
+        final CompileContext context = new CompileContext(units, errorHandler, writer, loader);
+
+        // create the compiler
+        final org.eclipse.jdt.internal.compiler.Compiler compiler =
                 new org.eclipse.jdt.internal.compiler.Compiler(
                         context,
-                        policy,
+                        this.policy,
                         settings,
                         context,
-                        PROBLEM_FACTORY,
-                        logWriter);
+                        this.problemFactory,
+                        null);
 
-        compiler.compile(context.sourceUnits());
+        // compile
+        compiler.compile(context.getSourceUnits());
 
-        context.cleanup();
-
-        return !context.hadErrors;
+        return !context.hasErrors;
     }
 
     //--------------------------------------------------------< inner classes >
 
-    private class CompileContext implements ICompilerRequestor, INameEnvironment {
-
-        boolean hadErrors;
-        HashMap<String,ICompilationUnit> compUnits;
+    private class CompileContext implements ICompilerRequestor, INameEnvironment, ErrorHandler {
 
-        ErrorHandler errorHandler;
-        ClassWriter classWriter;
+        private final Map<String,ICompilationUnit> compUnits;
 
-        CompilerEnvironment compEnv;
+        private final ErrorHandler errorHandler;
+        private final ClassLoaderWriter classLoaderWriter;
+        private final ClassLoader classLoader;
 
-        CompileContext(CompileUnit[] units,
-        		CompilerEnvironment compEnv,
-        		ErrorHandler errorHandler,
-        		ClassWriter classWriter) {
+        /** Flag indicating if we have an error. */
+        private boolean hasErrors = false;
 
-        	compUnits = new HashMap<String,ICompilationUnit>(units.length);
+        public CompileContext(final CompilationUnit[] units,
+         		              final ErrorHandler 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]);
+                CompilationUnitAdapter cua = new CompilationUnitAdapter(units[i], this);
                 char[][] compoundName = CharOperation.arrayConcat(cua.getPackageName(), cua.getMainTypeName());
-                compUnits.put(CharOperation.toString(compoundName), new CompilationUnitAdapter(units[i]));
+                this.compUnits.put(CharOperation.toString(compoundName), new CompilationUnitAdapter(units[i], this));
             }
 
-        	this.compEnv = compEnv;
         	this.errorHandler = errorHandler;
-            this.classWriter = classWriter;
-            hadErrors = false;
+            this.classLoaderWriter = classWriter;
+            this.classLoader = classLoader;
         }
 
-        ICompilationUnit[] sourceUnits() {
+        /**
+         * @see org.apache.sling.commons.compiler.ErrorHandler#onError(java.lang.String, java.lang.String, int, int)
+         */
+        public void onError(String msg, String sourceFile, int line, int position) {
+            this.errorHandler.onError(msg, sourceFile, line, position);
+            this.hasErrors = true;
+        }
+
+        /**
+         * @see org.apache.sling.commons.compiler.ErrorHandler#onWarning(java.lang.String, java.lang.String, int, int)
+         */
+        public void onWarning(String msg, String sourceFile, int line, int position) {
+            this.errorHandler.onWarning(msg, sourceFile, line, position);
+        }
+
+        public ICompilationUnit[] getSourceUnits() {
         	return compUnits.values().toArray(
         			new ICompilationUnit[compUnits.size()]);
         }
 
-        //---------------------------------------------------< ICompilerRequestor >
         /**
-         * {@inheritDoc}
+         * @see org.eclipse.jdt.internal.compiler.ICompilerRequestor#acceptResult(org.eclipse.jdt.internal.compiler.CompilationResult)
          */
         public void acceptResult(CompilationResult result) {
-            if (result.hasErrors()) {
-                hadErrors = true;
-            }
-
             if (result.hasProblems()) {
                 CategorizedProblem[] problems = result.getProblems();
                 for (int i = 0; i < problems.length; i++) {
@@ -174,11 +252,11 @@ public class EclipseJavaCompiler implements JavaCompiler {
                     int pos = problem.getSourceStart();
 
                     if (problem.isError()) {
-                        errorHandler.onError(msg, fileName, line, pos);
+                        this.onError(msg, fileName, line, pos);
                     } else if (problem.isWarning()) {
-                        errorHandler.onWarning(msg, fileName, line, pos);
+                        this.onWarning(msg, fileName, line, pos);
                     } else {
-                        log.debug("unknown problem category: " + problem.toString());
+                        logger.debug("unknown problem category: {}", problem);
                     }
                 }
             }
@@ -187,16 +265,15 @@ public class EclipseJavaCompiler implements JavaCompiler {
                 ClassFile classFile = classFiles[i];
                 String className = CharOperation.toString(classFile.getCompoundName());
                 try {
-                    classWriter.write(className, classFile.getBytes());
-                } catch (Exception e) {
-                    log.error("failed to persist class " + className, e);
+                    this.write(className, classFile.getBytes());
+                } catch (IOException e) {
+                    this.onError("Unable to write class file: " + e.getMessage(), className, 0, 0);
                 }
             }
         }
 
-        //-------------------------------------------------< INameEnvironment >
         /**
-         * {@inheritDoc}
+         * @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
@@ -208,7 +285,7 @@ public class EclipseJavaCompiler implements JavaCompiler {
 
             // locate the class through the class loader
             try {
-                byte[] bytes = compEnv.findClass(CharOperation.toString(compoundTypeName));
+                byte[] bytes = this.findClass(CharOperation.toString(compoundTypeName));
                 if (bytes == null) {
                     return null;
                 }
@@ -221,78 +298,145 @@ public class EclipseJavaCompiler implements JavaCompiler {
         }
 
         /**
-         * {@inheritDoc}
+         * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[], char[][])
          */
         public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
             return findType(CharOperation.arrayConcat(packageName, typeName));
         }
 
         /**
-         * {@inheritDoc}
+         * @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 && compEnv.isPackage(fqn);
+            return compUnits.get(fqn) == null && this.isPackage(fqn);
         }
 
         /**
-         * {@inheritDoc}
+         * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#cleanup()
          */
         public void cleanup() {
-            compEnv.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 {
 
-        CompileUnit compUnit;
-        char[][] packageName;
+        private final ErrorHandler errorHandler;
+        private final CompilationUnit compUnit;
+        private final String mainTypeName;
+        private final String packageName;
 
-        CompilationUnitAdapter(CompileUnit compUnit) {
+        public CompilationUnitAdapter(final CompilationUnit compUnit, final ErrorHandler 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);
+            }
         }
 
-        String extractPackageName(char[] contents) {
-            BufferedReader reader = new BufferedReader(new CharArrayReader(contents));
+        /**
+         * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents()
+         */
+        public char[] getContents() {
+            Reader fr = null;
             try {
-                String line;
-                while ((line = reader.readLine()) != null) {
-                    line = line.trim();
-                    if (line.startsWith("package")) {
-                        line = line.substring("package".length());
-                        line = line.substring(0, line.lastIndexOf(';'));
-                        return line.trim();
+                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) {
-                // should never get here...
+                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) {}
+                }
             }
-
-            // no package declaration found
-            return "";
-        }
-
-        //-------------------------------------------------< ICompilationUnit >
-
-        public char[] getContents() {
-            return compUnit.getSourceFileContents();
         }
 
+        /**
+         * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getMainTypeName()
+         */
         public char[] getMainTypeName() {
-            return compUnit.getMainTypeName().toCharArray();
+            return this.mainTypeName.toCharArray();
         }
 
+        /**
+         * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getPackageName()
+         */
         public char[][] getPackageName() {
-            if (packageName == null) {
-                String s = extractPackageName(compUnit.getSourceFileContents());
-                packageName = CharOperation.splitOn('.', s.toCharArray());
-            }
-            return packageName;
+            return CharOperation.splitOn('.', this.packageName.toCharArray());
         }
 
+        /**
+         * @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName()
+         */
         public char[] getFileName() {
-            return compUnit.getSourceFileName().toCharArray();
+            return (this.mainTypeName + ".java").toCharArray();
         }
     }
 }
diff --git a/src/main/resources/META-INF/NOTICE b/src/main/resources/META-INF/NOTICE
index d7953a3..03ad88a 100644
--- a/src/main/resources/META-INF/NOTICE
+++ b/src/main/resources/META-INF/NOTICE
@@ -1,5 +1,5 @@
 Apache Sling Java Compiler
-Copyright 2008-2009 The Apache Software Foundation
+Copyright 2008-2010 The Apache Software Foundation
 
 Apache Sling is based on source code originally developed 
 by Day Software (http://www.day.com/).
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
index 598eb33..c42b9b6 100644
--- a/src/test/java/org/apache/sling/commons/compiler/impl/CompilerJava5Test.java
+++ b/src/test/java/org/apache/sling/commons/compiler/impl/CompilerJava5Test.java
@@ -17,17 +17,16 @@
 package org.apache.sling.commons.compiler.impl;
 
 import java.io.ByteArrayOutputStream;
-import java.io.CharArrayWriter;
 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.compiler.ClassWriter;
-import org.apache.sling.commons.compiler.CompileUnit;
-import org.apache.sling.commons.compiler.CompilerEnvironment;
+import org.apache.sling.commons.classloader.ClassLoaderWriter;
+import org.apache.sling.commons.compiler.CompilationUnit;
 import org.apache.sling.commons.compiler.ErrorHandler;
 import org.apache.sling.commons.compiler.Options;
 
@@ -35,13 +34,18 @@ import org.apache.sling.commons.compiler.Options;
  * Test case for java 5 support
  */
 public class CompilerJava5Test extends TestCase
-        implements CompilerEnvironment, ErrorHandler, ClassWriter {
+        implements ErrorHandler, ClassLoaderWriter {
 
     public void testJava5Support() throws Exception {
         String sourceFile = "Java5Test";
 
-        CompileUnit unit = createCompileUnit(sourceFile);
-        new EclipseJavaCompiler().compile(new CompileUnit[]{unit}, this, this, this, new Options(Options.VERSION_1_5, true));
+        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());
+
+        assertTrue(new EclipseJavaCompiler().compile(new CompilationUnit[]{unit}, this, options));
     }
 
     //---------------------------------------------------------< ErrorHandler >
@@ -54,102 +58,62 @@ public class CompilerJava5Test extends TestCase
         System.out.println("Warning in " + sourceFile + ", line " + line + ", pos. " + position + ": " + msg);
     }
 
-    //--------------------------------------------------< CompilerEnvironment >
-
-    public byte[] findClass(String className) throws Exception {
-        ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        InputStream in = cl.getResourceAsStream(className.replace('.', '/') + ".class");
-        if (in == null) {
-            return null;
-        }
-        ByteArrayOutputStream out = new ByteArrayOutputStream(0x7fff);
-
-        try {
-            byte[] buffer = new byte[0x1000];
-            int read = 0;
-            while ((read = in.read(buffer)) > 0) {
-                out.write(buffer, 0, read);
-            }
-        } finally {
-            //out.close();
-            in.close();
-        }
+    //----------------------------------------------------------< ClassLoaderWriter >
 
-        return out.toByteArray();
-    }
+    //--------------------------------------------------------< misc. helpers >
 
-    public char[] findSource(String className) throws Exception {
-        return new char[0];
-    }
+    private CompilationUnit createCompileUnit(final String sourceFile) throws Exception {
+        return new CompilationUnit() {
 
-    public boolean isPackage(String packageName) {
-        ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        InputStream in = cl.getResourceAsStream(packageName.replace('.', '/') + ".class");
-        if (in != null) {
-            try {
-                in.close();
-            } catch (IOException ignore) {
+            /**
+             * @see org.apache.sling.commons.compiler.CompilationUnit#getMainClassName()
+             */
+            public String getMainClassName() {
+                return "org.apache.sling.commons.compiler.test." + sourceFile;
             }
-            return false;
-        }
-        return true;
-    }
 
-    public void cleanup() {
+            /**
+             * @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");
+            }
+        };
     }
 
-    //----------------------------------------------------------< ClassWriter >
-
-    public void write(String className, byte[] data) throws Exception {
-        // nothing to do
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#delete(java.lang.String)
+     */
+    public boolean delete(String path) {
+        return false;
     }
 
-    //--------------------------------------------------------< misc. helpers >
-
-    private CompileUnit createCompileUnit(final String sourceFile) throws Exception {
-        final char[] chars = readTextResource(sourceFile);
-
-        return new CompileUnit() {
-
-            public String getSourceFileName() {
-                return sourceFile;
-            }
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getInputStream(java.lang.String)
+     */
+    public InputStream getInputStream(String path) throws IOException {
+        return null;
+    }
 
-            public char[] getSourceFileContents() {
-                return chars;
-            }
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getLastModified(java.lang.String)
+     */
+    public long getLastModified(String path) {
+        return 0;
+    }
 
-            public String getMainTypeName() {
-                String className;
-                int pos = sourceFile.lastIndexOf(".java");
-                if (pos != -1) {
-                    className = sourceFile.substring(0, pos).trim();
-                } else {
-                    className = sourceFile.trim();
-                }
-                pos = className.lastIndexOf('/');
-                return (pos == -1) ? className : className.substring(pos);
-            }
-        };
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getOutputStream(java.lang.String)
+     */
+    public OutputStream getOutputStream(String path) {
+        return new ByteArrayOutputStream();
     }
 
-    private char[] readTextResource(String resourcePath) throws IOException {
-        InputStream in = getClass().getClassLoader().getResourceAsStream(resourcePath);
-        if (in == null) {
-            throw new IOException("resource not found");
-        }
-        Reader reader = new InputStreamReader(in);
-        CharArrayWriter writer = new CharArrayWriter(0x7fff);
-        try {
-            char[] buffer = new char[0x1000];
-            int read = 0;
-            while ((read = reader.read(buffer)) > 0) {
-                writer.write(buffer, 0, read);
-            }
-            return writer.toCharArray();
-        } finally {
-            //writer.close();
-            reader.close();
-        }
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#rename(java.lang.String, java.lang.String)
+     */
+    public boolean rename(String oldPath, String newPath) {
+        return false;
     }
 }
diff --git a/src/test/resources/Java5Test b/src/test/resources/Java5Test
index 83bf4ac..44658bc 100644
--- a/src/test/resources/Java5Test
+++ b/src/test/resources/Java5Test
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package  org.apache.sling.commons.compiler.test ;
+package org.apache.sling.commons.compiler.test;
 
 import java.util.List;
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.