SLING-874 : Use new commons compiler for java servlet scripting

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@926970 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index db84dac..12fb9a3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,17 +90,11 @@
             <version>2.0.2-incubator</version>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.commons.classloader</artifactId>
-            <version>1.0.0</version>
-            <scope>provided</scope>
-        </dependency>
 
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.compiler</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.1-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/src/main/java/org/apache/sling/scripting/java/impl/CompilationUnit.java b/src/main/java/org/apache/sling/scripting/java/impl/CompilationUnit.java
index 86660af..81d386f 100644
--- a/src/main/java/org/apache/sling/scripting/java/impl/CompilationUnit.java
+++ b/src/main/java/org/apache/sling/scripting/java/impl/CompilationUnit.java
@@ -16,165 +16,54 @@
  */
 package org.apache.sling.scripting.java.impl;
 
-import java.io.BufferedReader;
-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 java.util.ArrayList;
-import java.util.List;
-
-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.compiler.ErrorHandler;
 
 
 public class CompilationUnit
-    implements CompileUnit, CompilerEnvironment, ErrorHandler, ClassWriter {
+    implements org.apache.sling.commons.compiler.CompilationUnit {
 
     private final SlingIOProvider ioProvider;
     private final String className;
     private final String sourceFile;
 
-    /** The list of compile errors - this is created lazily. */
-    private List<CompilerError> errors;
-
-    public CompilationUnit(String sourceFile,
-                           String className,
-                           SlingIOProvider ioProvider) {
+    public CompilationUnit(final String sourceFile,
+                           final String className,
+                           final SlingIOProvider ioProvider) {
         this.className = className;
         this.sourceFile = sourceFile;
         this.ioProvider = ioProvider;
     }
 
     /**
-     * @see org.apache.sling.commons.compiler.CompileUnit#getSourceFileName()
+     * @see org.apache.sling.commons.compiler.CompilationUnit#getMainClassName()
      */
-    public String getSourceFileName() {
-        return getMainTypeName() + ".java";
+    public String getMainClassName() {
+        return this.className;
     }
 
     /**
-     * @see org.apache.sling.commons.compiler.CompileUnit#getSourceFileContents()
+     * @see org.apache.sling.commons.compiler.CompilationUnit#getSource()
      */
-    public char[] getSourceFileContents() {
-        char[] result = null;
+    public Reader getSource() throws IOException {
         InputStream fr = null;
         try {
             fr = ioProvider.getInputStream(this.sourceFile);
-            final Reader reader = new BufferedReader(new InputStreamReader(fr, ioProvider.getOptions().getJavaEncoding()));
-            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);
-                }
-                result = new char[buf.length()];
-                buf.getChars(0, result.length, result, 0);
-            } finally {
-                reader.close();
-            }
+            return new InputStreamReader(fr, ioProvider.getOptions().getJavaEncoding());
         } catch (IOException e) {
-            this.onError(e.getMessage(), this.sourceFile, 0, 0);
-        }
-        return result;
-    }
-
-    /**
-     * @see org.apache.sling.commons.compiler.CompileUnit#getMainTypeName()
-     */
-    public String getMainTypeName() {
-        int dot = className.lastIndexOf('.');
-        if (dot > 0) {
-            return className.substring(dot + 1);
-        }
-        return className;
-    }
-
-    /**
-     * @see org.apache.sling.commons.compiler.CompilerEnvironment#isPackage(java.lang.String)
-     */
-    public boolean isPackage(String result) {
-        if (result.equals(this.className)) {
-            return false;
-        }
-        String resourceName = result.replace('.', '/') + ".class";
-        if ( resourceName.startsWith("/") ) {
-            resourceName = resourceName.substring(1);
-        }
-        final InputStream is = this.ioProvider.getClassLoader().getResourceAsStream(resourceName);
-        if ( is != null ) {
-            try {
-                is.close();
-            } catch (IOException ignore) {}
-        }
-        return is == null;
-    }
-
-    /**
-     * @see org.apache.sling.commons.compiler.CompilerEnvironment#findClass(java.lang.String)
-     */
-    public byte[] findClass(String name) throws Exception {
-        final String resourceName = name.replace('.', '/') + ".class";
-        final InputStream is = this.ioProvider.getClassLoader().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) {}
+            if ( fr != null ) {
+                try { fr.close(); } catch (IOException ignore) {}
             }
+            throw e;
         }
-        return null;
     }
 
     /**
-     * @see org.apache.sling.commons.compiler.CompilerEnvironment#cleanup()
+     * @see org.apache.sling.commons.compiler.CompilationUnit#getLastModified()
      */
-    public void cleanup() {
-        // EMPTY
-    }
-
-    /**
-     * @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) {
-        if ( errors == null ) {
-            errors = new ArrayList<CompilerError>();
-        }
-        errors.add(new CompilerError(sourceFile, line, position, msg));
-    }
-
-    /**
-     * @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) {
-        // we ignore warnings
-    }
-
-    /**
-     * @see org.apache.sling.commons.compiler.ClassWriter#write(java.lang.String, byte[])
-     */
-    public void write(String name, byte[] data) throws Exception {
-        final OutputStream os = this.ioProvider.getOutputStream('/' + name.replace('.', '/') + ".class");
-        os.write(data);
-        os.close();
-    }
-
-    /** Return the list of errors. */
-    public List<CompilerError> getErrors() throws IOException {
-        return errors;
+    public long getLastModified() {
+        return this.ioProvider.lastModified(this.sourceFile);
     }
 }
diff --git a/src/main/java/org/apache/sling/scripting/java/impl/CompilerError.java b/src/main/java/org/apache/sling/scripting/java/impl/CompilerError.java
deleted file mode 100644
index 4f7dcb9..0000000
--- a/src/main/java/org/apache/sling/scripting/java/impl/CompilerError.java
+++ /dev/null
@@ -1,100 +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.scripting.java.impl;
-
-/**
- * This class encapsulates an error message produced by a programming language
- * processor (whether interpreted or compiled)
- */
-public class CompilerError {
-
-    /**
-     * The start line number of the offending program text
-     */
-    private final int startline;
-
-    /**
-     * The start column number of the offending program text
-     */
-    private final int startcolumn;
-
-    /**
-     * The name of the file containing the offending program text
-     */
-    private final String file;
-
-    /**
-     * The actual error text produced by the language processor
-     */
-    private final String message;
-
-    /**
-     * The error message constructor.
-     *
-     * @param file The name of the file containing the offending program text
-     * @param startline The start line number of the offending program text
-     * @param startcolumn The start column number of the offending program text
-     * @param message The actual error text produced by the language processor
-     */
-    public CompilerError(final String file,
-                         final int startline,
-                         final int startcolumn,
-                         final String message) {
-        this.file = file;
-        this.startline = startline;
-        this.startcolumn = startcolumn;
-        this.message = message;
-    }
-
-    /**
-     * Return the filename associated with this compiler error.
-     *
-     * @return The filename associated with this compiler error
-     */
-    public String getFile() {
-        return file;
-    }
-
-    /**
-     * Return the starting line number of the program text originating this error
-     *
-     * @return The starting line number of the program text originating this error
-     */
-    public int getStartLine() {
-        return startline;
-    }
-
-    /**
-     * Return the starting column number of the program text originating this
-     * error
-     *
-     * @return The starting column number of the program text originating this
-     * error
-     */
-    public int getStartColumn() {
-        return startcolumn;
-    }
-
-    /**
-     * Return the message produced by the language processor
-     *
-     * @return The message produced by the language processor
-     */
-    public String getMessage() {
-        return message;
-    }
-}
diff --git a/src/main/java/org/apache/sling/scripting/java/impl/CompilerOptions.java b/src/main/java/org/apache/sling/scripting/java/impl/CompilerOptions.java
index 18ce68e..056373a 100644
--- a/src/main/java/org/apache/sling/scripting/java/impl/CompilerOptions.java
+++ b/src/main/java/org/apache/sling/scripting/java/impl/CompilerOptions.java
@@ -32,14 +32,16 @@
         CompilerOptions opts = new CompilerOptions();
 
         final Boolean classDebugInfo = (Boolean)props.get(JavaScriptEngineFactory.PROPERTY_CLASSDEBUGINFO);
-        opts.setGenerateDebugInfo(classDebugInfo != null ? classDebugInfo : true);
+        opts.put(Options.KEY_GENERATE_DEBUG_INFO, classDebugInfo != null ? classDebugInfo : true);
 
         final String sourceVM = (String) props.get(JavaScriptEngineFactory.PROPERTY_COMPILER_SOURCE_V_M);
-        opts.setSourceVersion(sourceVM != null && sourceVM.length() > 0 ? sourceVM : JavaScriptEngineFactory.DEFAULT_VM_VERSION);
+        opts.put(Options.KEY_SOURCE_VERSION, sourceVM != null && sourceVM.length() > 0 ? sourceVM : JavaScriptEngineFactory.DEFAULT_VM_VERSION);
 
         final String encoding = (String) props.get(JavaScriptEngineFactory.PROPERTY_ENCODING);
         opts.encoding = encoding != null && encoding.length() > 0 ? encoding : "UTF-8";
 
+        opts.put(Options.KEY_IGNORE_WARNINGS, true);
+
         return opts;
     }
 
diff --git a/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java
index 81e167f..3795897 100644
--- a/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java
+++ b/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java
@@ -41,8 +41,6 @@
 import org.apache.sling.api.scripting.SlingScript;
 import org.apache.sling.api.scripting.SlingScriptConstants;
 import org.apache.sling.api.scripting.SlingScriptHelper;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.apache.sling.commons.compiler.JavaCompiler;
 import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
 import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
@@ -79,24 +77,11 @@
     /**
      * @scr.reference
      */
-    private DynamicClassLoaderManager dynamicClassLoaderManager;
-
-    /**
-     * @scr.reference
-     */
     private JavaCompiler javaCompiler;
 
-    /**
-     * The class loader
-     */
-    private ClassLoader javaClassLoader;
-
     /** @scr.reference */
     private ServletContext slingServletContext;
 
-    /** @scr.reference */
-    private ClassLoaderWriter classLoaderWriter;
-
     private SlingIOProvider ioProvider;
 
     private JavaServletContext javaServletContext;
@@ -141,9 +126,7 @@
      */
     @SuppressWarnings("unchecked")
     protected void activate(final ComponentContext componentContext) {
-        this.ioProvider = new SlingIOProvider(this.classLoaderWriter,
-                                              this.javaCompiler,
-                                              this.javaClassLoader,
+        this.ioProvider = new SlingIOProvider(this.javaCompiler,
                                               CompilerOptions.createOptions(componentContext.getProperties()));
         this.javaServletContext = new JavaServletContext(ioProvider,
             slingServletContext);
@@ -248,44 +231,6 @@
     }
 
     /**
-     * Bind the class load provider.
-     * @param repositoryClassLoaderProvider the new provider
-     */
-    protected void bindDynamicClassLoaderManager(DynamicClassLoaderManager rclp) {
-        if ( this.javaClassLoader != null ) {
-            this.ungetClassLoader();
-        }
-        this.getClassLoader(rclp);
-    }
-
-    /**
-     * Unbind the class loader provider.
-     * @param repositoryClassLoaderProvider the old provider
-     */
-    protected void unbindDynamicClassLoaderManager(DynamicClassLoaderManager rclp) {
-        if ( this.dynamicClassLoaderManager == rclp ) {
-            this.ungetClassLoader();
-        }
-    }
-
-    /**
-     * Get the class loader
-     */
-    private void getClassLoader(DynamicClassLoaderManager rclp) {
-        this.dynamicClassLoaderManager = rclp;
-        this.javaClassLoader = rclp.getDynamicClassLoader();
-    }
-
-    /**
-     * Unget the class loader
-     */
-    private void ungetClassLoader() {
-        this.dynamicClassLoaderManager = null;
-        this.javaClassLoader = null;
-    }
-    // ---------- Internal -----------------------------------------------------
-
-    /**
      * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
      */
     public void handleEvent(Event event) {
diff --git a/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java b/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java
index 536f4c5..ba38f94 100644
--- a/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java
+++ b/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java
@@ -17,7 +17,6 @@
 
 package org.apache.sling.scripting.java.impl;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.List;
 
@@ -29,7 +28,8 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.sling.commons.compiler.CompileUnit;
+import org.apache.sling.commons.compiler.CompilationResult;
+import org.apache.sling.commons.compiler.CompilerMessage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -77,23 +77,6 @@
     }
 
     /**
-     * Get the servlet.
-     * @throws ServletException
-     * @throws IOException
-     * @throws FileNotFoundException
-     */
-    private void getServlet()
-    throws IllegalAccessException, InstantiationException, ClassNotFoundException, ServletException {
-        destroy();
-
-        this.servletClass = this.ioProvider.getClassLoader().loadClass(this.className);
-        final Servlet servlet = (Servlet) servletClass.newInstance();
-        servlet.init(config);
-
-        theServlet = servlet;
-    }
-
-    /**
      * Call the servlet.
      * @param request The current request.
      * @param response The current response.
@@ -122,12 +105,9 @@
                 synchronized (this) {
                     if (this.lastModificationTest == 0 ) {
                         try {
-                            if ( this.compile() || this.theServlet == null ) {
-                                // clear exception
-                                this.compileException = null;
-                                // (re)load the servlet class
-                                getServlet();
-                            }
+                            // clear exception
+                            this.compileException = null;
+                            this.compile();
                         } catch (Exception ex) {
                             // store exception for futher access attempts
                             this.compileException = ex;
@@ -186,48 +166,38 @@
         this.lastModificationTest = 0;
     }
 
-    /**
-     * Check if the compiled class file is older than the source file
-     */
-    private boolean isOutDated() {
-        if ( this.lastModificationTest > 0 ) {
-            return false;
+    private void compile() throws Exception {
+        final CompilationUnit unit = new CompilationUnit(this.sourcePath, className, ioProvider);
+        final CompilationResult result = this.ioProvider.getCompiler().compile(new org.apache.sling.commons.compiler.CompilationUnit[] {unit},
+                ioProvider.getOptions());
+
+        final List<CompilerMessage> errors = result.getErrors();
+        if ( errors != null && errors.size() > 0 ) {
+            throw CompilerException.create(errors);
         }
-        final long sourceLastModified = this.ioProvider.lastModified(this.sourcePath);
+        if ( result.didCompile() || this.theServlet == null ) {
+            destroy();
 
-        final long targetLastModified = this.ioProvider.lastModified('/' + this.className.replace('.', '/') + ".class");
-        if (targetLastModified < 0) {
-            return true;
+            this.servletClass = result.loadCompiledClass(this.className);
+            final Servlet servlet = (Servlet) servletClass.newInstance();
+            servlet.init(config);
+
+            theServlet = servlet;
+
         }
-
-        return targetLastModified < sourceLastModified;
-    }
-
-    private boolean compile() throws Exception {
-        if (this.isOutDated()) {
-            final CompilationUnit unit = new CompilationUnit(this.sourcePath, className, ioProvider);
-            this.ioProvider.getCompiler().compile(new CompileUnit[] {unit}, unit, unit, unit, ioProvider.getOptions());
-
-            final List<CompilerError> errors = unit.getErrors();
-            if ( errors != null && errors.size() > 0 ) {
-                throw CompilerException.create(errors);
-            }
-            return true;
-        }
-        return false;
     }
 
     protected final static class CompilerException extends ServletException {
 
-        public static CompilerException create(List<CompilerError> errors) {
+        public static CompilerException create(List<CompilerMessage> errors) {
             final StringBuilder buffer = new StringBuilder();
             buffer.append("Compilation errors:\n");
-            for(final CompilerError e : errors) {
+            for(final CompilerMessage e : errors) {
                 buffer.append(e.getFile());
                 buffer.append(", line ");
-                buffer.append(e.getStartLine());
+                buffer.append(e.getLine());
                 buffer.append(", column ");
-                buffer.append(e.getStartColumn());
+                buffer.append(e.getColumn());
                 buffer.append(" : " );
                 buffer.append(e.getMessage());
                 buffer.append("\n");
diff --git a/src/main/java/org/apache/sling/scripting/java/impl/SlingIOProvider.java b/src/main/java/org/apache/sling/scripting/java/impl/SlingIOProvider.java
index 836ac2e..fdba2e7 100644
--- a/src/main/java/org/apache/sling/scripting/java/impl/SlingIOProvider.java
+++ b/src/main/java/org/apache/sling/scripting/java/impl/SlingIOProvider.java
@@ -19,7 +19,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.HashSet;
@@ -30,7 +29,6 @@
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceMetadata;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
 import org.apache.sling.commons.compiler.JavaCompiler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -45,18 +43,11 @@
 
     private ThreadLocal<ResourceResolver> requestResourceResolver;
 
-    private final ClassLoaderWriter classLoaderWriter;
-
     private final JavaCompiler compiler;
 
     private final CompilerOptions options;
 
     /**
-     * Classloader
-     */
-    private final ClassLoader classLoader;
-
-    /**
      * Servlet cache.
      */
     private final ServletCache servletCache = new ServletCache();
@@ -64,14 +55,10 @@
     /**
      * Constructor.
      */
-    SlingIOProvider(final ClassLoaderWriter classLoaderWriter,
-                    final JavaCompiler compiler,
-                    final ClassLoader classLoader,
+    SlingIOProvider(final JavaCompiler compiler,
                     final CompilerOptions options) {
         this.requestResourceResolver = new ThreadLocal<ResourceResolver>();
-        this.classLoaderWriter = classLoaderWriter;
         this.compiler = compiler;
-        this.classLoader = classLoader;
         this.options = options;
     }
 
@@ -93,10 +80,6 @@
         return this.compiler;
     }
 
-    public ClassLoader getClassLoader() {
-        return this.classLoader;
-    }
-
     public CompilerOptions getOptions() {
         return this.options;
     }
@@ -113,12 +96,12 @@
     public InputStream getInputStream(String fileName)
     throws FileNotFoundException, IOException {
         try {
-            Resource resource = getResourceInternal(fileName);
+            final Resource resource = getResourceInternal(fileName);
             if (resource == null) {
                 throw new FileNotFoundException("Cannot find " + fileName);
             }
 
-            InputStream stream = resource.adaptTo(InputStream.class);
+            final InputStream stream = resource.adaptTo(InputStream.class);
             if (stream == null) {
                 throw new FileNotFoundException("Cannot find " + fileName);
             }
@@ -138,14 +121,11 @@
      * returned.
      */
     public long lastModified(String fileName) {
-        if ( fileName.endsWith(".class") ) {
-            return this.classLoaderWriter.getLastModified(fileName);
-        }
         try {
-            Resource resource = getResourceInternal(fileName);
+            final Resource resource = getResourceInternal(fileName);
             if (resource != null) {
-                ResourceMetadata meta = resource.getResourceMetadata();
-                long modTime = meta.getModificationTime();
+                final ResourceMetadata meta = resource.getResourceMetadata();
+                final long modTime = meta.getModificationTime();
                 return (modTime > 0) ? modTime : 0;
             }
 
@@ -157,13 +137,6 @@
         return -1;
     }
 
-    /**
-     * Returns an output stream to write to the repository.
-     */
-    public OutputStream getOutputStream(String fileName) {
-        return this.classLoaderWriter.getOutputStream(fileName);
-    }
-
     public URL getURL(String path) throws MalformedURLException {
         try {
             final Resource resource = getResourceInternal(path);