incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1304391 [1/2] - in /sling/trunk: bundles/commons/classloader/ bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/ bundles/jcr/...
Date Fri, 23 Mar 2012 14:53:40 GMT
Author: cziegeler
Date: Fri Mar 23 14:53:38 2012
New Revision: 1304391

URL: http://svn.apache.org/viewvc?rev=1304391&view=rev
Log:
SLING-2447 : ClassLoaderWriter should provide class loader for loading written classes/resources

Added:
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java   (with props)
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java   (with props)
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java   (with props)
    sling/trunk/contrib/commons/compiler/src/main/java/org/apache/sling/commons/compiler/impl/IsolatedClassLoader.java   (with props)
Removed:
    sling/trunk/bundles/jcr/classloader/LICENSE
    sling/trunk/bundles/jcr/classloader/NOTICE
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderResource.java
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassPathEntry.java
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicClassLoaderProviderImpl.java
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicRepositoryClassLoader.java
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java
    sling/trunk/bundles/jcr/classloader/src/main/resources/META-INF/
Modified:
    sling/trunk/bundles/commons/classloader/pom.xml
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderProvider.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java
    sling/trunk/bundles/jcr/classloader/pom.xml
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/Util.java
    sling/trunk/bundles/scripting/jsp/pom.xml
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspServletOptions.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/SlingIOProvider.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IOProvider.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/Options.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JDTCompiler.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JspRuntimeContext.java
    sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServlet.java
    sling/trunk/contrib/commons/compiler/pom.xml
    sling/trunk/contrib/commons/compiler/src/main/java/org/apache/sling/commons/compiler/impl/CompilationResultImpl.java
    sling/trunk/contrib/commons/compiler/src/main/java/org/apache/sling/commons/compiler/impl/EclipseJavaCompiler.java
    sling/trunk/contrib/commons/compiler/src/test/java/org/apache/sling/commons/compiler/impl/CompilerJava5Test.java
    sling/trunk/contrib/scripting/java/pom.xml
    sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java
    sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java

Modified: sling/trunk/bundles/commons/classloader/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/pom.xml?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/pom.xml (original)
+++ sling/trunk/bundles/commons/classloader/pom.xml Fri Mar 23 14:53:38 2012
@@ -67,7 +67,7 @@
                             org.apache.sling.commons.classloader.impl.Activator
                         </Bundle-Activator>
                         <Export-Package>
-                            org.apache.sling.commons.classloader;version=1.2.0
+                            org.apache.sling.commons.classloader;version=1.3.0
                         </Export-Package>
                         <Private-Package>
                             org.apache.sling.commons.classloader.impl

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java Fri Mar 23 14:53:38 2012
@@ -23,10 +23,13 @@ import java.io.InputStream;
 import java.io.OutputStream;
 
 /**
- * The class loader writer allows to modify the resources loaded by a
- * {@link DynamicClassLoaderProvider}. For example a class loader writer
- * could write generated class files into the repository or the temporary
- * file system.
+ * A class loader writer is a service allowing to dynamically generate
+ * classes and resources.
+ * It provides methods for writing, removing, and moving resources.
+ * In addition it provides a dynamic class loader which can be used
+ * to dynamically load generated classes.
+ * For example a class loader writer could write generated class files
+ * into the repository or the temporary file system.
  */
 public interface ClassLoaderWriter {
 
@@ -34,7 +37,8 @@ public interface ClassLoaderWriter {
      * Get the output stream for a class or resource handled
      * by the underlying class loader.
      * If the resource/class does not exists it should be created.
-     * @param path The path of the class/resource.
+     * @param path The path of the class/resource. The path should be
+     *             absolute like /com/my/domain/HelloWorld.class
      * @return The output stream.
      */
     OutputStream getOutputStream(String path);
@@ -42,7 +46,8 @@ public interface ClassLoaderWriter {
     /**
      * Get the input stream for a class or resource handled
      * by the underlying class loader.
-     * @param path The path of the class/resource.
+     * @param path The path of the class/resource. The path should be
+     *             absolute like /com/my/domain/HelloWorld.class
      * @return The input stream for the resource/class.
      * @throws IOException If the resource/class does not exist.
      */
@@ -50,7 +55,8 @@ public interface ClassLoaderWriter {
 
     /**
      * Return the last modified for the class or resource.
-     * @param path The path of the class/resource.
+     * @param path The path of the class/resource. The path should be
+     *             absolute like /com/my/domain/HelloWorld.class
      * @return The last modified information or <code>-1</code> if
      *         the information can't be detected.
      */
@@ -58,17 +64,38 @@ public interface ClassLoaderWriter {
 
     /**
      * Delete the class/resource
-     * @param path The path of the class/resource.
+     * @param path The path of the class/resource. The path should be
+     *             absolute like /com/my/domain/HelloWorld.class
      * @return <code>true</code> if the resource exists and could be deleted,
      *     <code>false</code> otherwise.
      */
     boolean delete(String path);
 
     /**
-     * Rename a class/resource.
+     * Rename a class/resource. The paths should be
+     * absolute like /com/my/domain/HelloWorld.class
      * @param oldPath The path of the class/resource.
      * @param newPath The new path.
      * @return <code>true</code> if the renaming has been successful.
      */
     boolean rename(String oldPath, String newPath);
+
+    /**
+     * Get a dynamic class loader.
+     * The returned class loader can be used to load classes and resources generated
+     * through this class loader writer. The parent of this class loader is
+     * a class loader from the {@link DynamicClassLoaderManager}.
+     * The class loader returned by this method should not be cached, as it might
+     * get stale (e.g. used classes are removed etc.). Therefore each time a newly
+     * generated class is loaded, the class loader should be fetched again using
+     * this method.
+     * The implementation might cache the class loader and return the same loader
+     * on subsequent calls for as long as possible.
+     * Clients of the class loader can use the {@link DynamicClassLoader#isLive()}
+     * method to check if the fetched instance can still be used.
+     *
+     * @return A dynamic class loader implementing {@link DynamicClassLoader}
+     * @since 1.3
+     */
+    ClassLoader getClassLoader();
 }

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java Fri Mar 23 14:53:38 2012
@@ -26,9 +26,7 @@ package org.apache.sling.commons.classlo
  * classes.
  *
  * The default implementation uses the package admin
- * service to load classes and resources. The search
- * path can be extended by providing
- * {@link DynamicClassLoaderProvider}s.
+ * service to load classes and resources.
  *
  * Keep in mind, that the class loader might get invalid.
  * This happens for example, if the class loader loaded
@@ -37,7 +35,7 @@ package org.apache.sling.commons.classlo
  *
  * In these cases, the dynamic class loader manager service
  * is unregistered and reregistered again, so you should
- * reget your classloader and invalidate loaded objects
+ * discard your classloader and invalidate loaded objects
  * whenever this happens.
  */
 public interface DynamicClassLoaderManager {

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderProvider.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderProvider.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderProvider.java Fri Mar 23 14:53:38 2012
@@ -24,7 +24,12 @@ package org.apache.sling.commons.classlo
  * class loading mechanism. For instance a JCR class loader
  * provider could provide some class loader loading classes
  * from a content repository etc.
+ *
+ * @deprecated The dynamic class loader provider is not supported
+ *             anymore and any service implementing this is not
+ *             considered for dynamic class loading anymore!
  */
+@Deprecated
 public interface DynamicClassLoaderProvider {
 
     /**

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java Fri Mar 23 14:53:38 2012
@@ -16,41 +16,36 @@
  */
 package org.apache.sling.commons.classloader.impl;
 
-import java.util.Arrays;
-import java.util.Comparator;
-
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.apache.sling.commons.classloader.DynamicClassLoaderProvider;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * This is the default implementation of the dynamic class loader
  * manager.
  */
 public class DynamicClassLoaderManagerImpl
-    extends ServiceTracker
     implements DynamicClassLoaderManager {
 
-    /** The package admin class loader. */
-    private final PackageAdminClassLoader pckAdminCL;
+    /** Logger. */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /** The class loaders */
+    private final ClassLoader[] loaders;
 
     /** The dynamic class loader. */
     private final ClassLoaderFacade facade;
 
-    /** The cached chain of class loaders. */
-    private ClassLoader[] cache;
-
-    /** The cached chain of dynamic class loader providers. */
-    private DynamicClassLoaderProvider[] providerCache;
-
     /** Is this still active? */
     private volatile boolean active = true;
 
-    /** Tracking count */
-    private volatile int trackingCount = -1;
+    private final ServiceTracker deprecatedProviderTracker;
 
     /**
      * Create a new service instance
@@ -62,69 +57,39 @@ public class DynamicClassLoaderManagerIm
             final PackageAdmin pckAdmin,
             final ClassLoader parent,
             final DynamicClassLoaderManagerFactory factory) {
-        super(ctx, DynamicClassLoaderProvider.class.getName(), null);
-        this.pckAdminCL = new PackageAdminClassLoader(pckAdmin, parent, factory);
-        this.cache = new ClassLoader[] {this.pckAdminCL};
-        this.providerCache = new DynamicClassLoaderProvider[0];
-        this.open();
-        this.facade = new ClassLoaderFacade(this);
-    }
+        this.deprecatedProviderTracker = new ServiceTracker(ctx, DynamicClassLoaderProvider.class.getName(),
+                new ServiceTrackerCustomizer() {
 
-    private synchronized void updateCache() {
-        if ( this.trackingCount < this.getTrackingCount() ) {
-            final ServiceReference[] refs = this.getServiceReferences();
-            final ClassLoader[] loaders;
-            final DynamicClassLoaderProvider[] providers;
-            if ( refs == null || refs.length == 0 ) {
-                loaders = new ClassLoader[] {this.pckAdminCL};
-                providers = new DynamicClassLoaderProvider[0];
-            } else {
-                loaders = new ClassLoader[1 + refs.length];
-                providers = new DynamicClassLoaderProvider[refs.length];
-                Arrays.sort(refs, ServiceReferenceComparator.INSTANCE);
-                int index = 0;
-                for(final ServiceReference ref : refs) {
-                    final DynamicClassLoaderProvider provider = (DynamicClassLoaderProvider)this.getService(ref);
-                    if ( provider != null ) {
-                        loaders[index] = provider.getClassLoader(this.pckAdminCL);
-                        providers[index] = provider;
+                    public void removedService(final ServiceReference serviceRef,
+                            final Object paramObject) {
+                        ctx.ungetService(serviceRef);
                     }
-                    index++;
-                }
-                loaders[index] = this.pckAdminCL;
-            }
-            // release old class loaders
-            this.releaseProviders();
-
-            // and now use new array
-            this.cache = loaders;
-            this.providerCache = providers;
-            this.trackingCount = this.getTrackingCount();
-        }
-    }
 
-    /**
-     * Free used class loader providers
-     */
-    private void releaseProviders() {
-        if ( this.providerCache != null ) {
-            for(int i=0; i<this.providerCache.length; i++) {
-                if ( this.cache[i] != null ) {
-                    this.providerCache[i].release(this.cache[i]);
-                }
-            }
-        }
+                    public void modifiedService(final ServiceReference serviceRef,
+                            final Object paramObject) {
+                        // nothing to do
+                    }
+
+                    public Object addingService(final ServiceReference serviceRef) {
+                        final Object obj = ctx.getService(serviceRef);
+                        if ( obj != null ) {
+                            logger.warn("Dynamic class loader does not support deprecated dynamic class loader providers: {} : {}",
+                                serviceRef, obj);
+                        }
+                        return obj;
+                    }
+                });
+        this.deprecatedProviderTracker.open();
+        this.loaders = new ClassLoader[] {new PackageAdminClassLoader(pckAdmin, parent, factory)};
+        this.facade = new ClassLoaderFacade(this);
     }
 
     /**
      * Deactivate this service.
      */
     public void deactivate() {
-        this.releaseProviders();
+        this.deprecatedProviderTracker.close();
         this.active = false;
-        this.close();
-        this.providerCache = null;
-        this.cache = null;
     }
 
     /**
@@ -142,26 +107,10 @@ public class DynamicClassLoaderManagerIm
     }
 
     /**
-     * This list contains the current list of class loaders. The first class loader
-     * is always the package admin class loader, therefore this list is never null
-     * and has always a size greater than zero.
-     * @return The list of class loaders.
+     * Return the dynamic class loaders to use
+     * Currently this is just the package admin class loader.
      */
     public ClassLoader[] getDynamicClassLoaders() {
-        if ( this.trackingCount < this.getTrackingCount() ) {
-            updateCache();
-        }
-        return this.cache;
-    }
-
-    /**
-     * Comparator for service references.
-     */
-    protected static final class ServiceReferenceComparator implements Comparator<ServiceReference> {
-        public static ServiceReferenceComparator INSTANCE = new ServiceReferenceComparator();
-
-        public int compare(ServiceReference o1, ServiceReference o2) {
-            return o1.compareTo(o2);
-        }
+        return this.loaders;
     }
 }

Modified: sling/trunk/bundles/jcr/classloader/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/pom.xml?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/classloader/pom.xml (original)
+++ sling/trunk/bundles/jcr/classloader/pom.xml Fri Mar 23 14:53:38 2012
@@ -80,6 +80,11 @@
         </plugins>
     </reporting>
     <dependencies>
+      <!-- SCR Annotations -->
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+        </dependency>
        <dependency>
            <groupId>javax.jcr</groupId>
            <artifactId>jcr</artifactId>
@@ -93,13 +98,13 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.classloader</artifactId>
-            <version>1.2.0</version>
+            <version>1.2.5-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.mime</artifactId>
-            <version>2.1.0-incubator</version>
+            <version>2.1.4</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

Added: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java?rev=1304391&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java (added)
+++ sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java Fri Mar 23 14:53:38 2012
@@ -0,0 +1,471 @@
+/*
+ * 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.jcr.classloader.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+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.mime.MimeTypeService;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>DynamicClassLoaderProviderImpl</code> provides
+ * a class loader which loads classes from configured paths
+ * in the repository.
+ * It implements the {@link ClassLoaderWriter} interface
+ * for clients to use for writing and reading such
+ * classes and resources.
+ */
+@Component(metatype=true, label="%loader.name", description="%loader.description",
+           name="org.apache.sling.jcr.classloader.internal.DynamicClassLoaderProviderImpl")
+@Service(value=ClassLoaderWriter.class)
+@Properties({
+    @org.apache.felix.scr.annotations.Property(name="service.vendor", value="The Apache Software Foundation"),
+    @org.apache.felix.scr.annotations.Property(name="service.description", value="Repository based classloader writer")
+})
+public class ClassLoaderWriterImpl
+    implements ClassLoaderWriter {
+
+    /** Logger */
+    private final Logger logger = LoggerFactory.getLogger(ClassLoaderWriterImpl.class);
+
+    private static final String CLASS_PATH_DEFAULT = "/var/classes";
+
+    @org.apache.felix.scr.annotations.Property(value=CLASS_PATH_DEFAULT)
+    private static final String CLASS_PATH_PROP = "classpath";
+
+
+    /** Node type for packages/folders. */
+    private static final String NT_FOLDER = "nt:folder";
+
+    /** Default class loader owner. */
+    private static final String OWNER_DEFAULT = "admin";
+
+    @org.apache.felix.scr.annotations.Property(value=OWNER_DEFAULT)
+    private static final String OWNER_PROP = "owner";
+
+    /** The owner of the class loader / jcr user. */
+    private String classLoaderOwner;
+
+    @Reference
+    private SlingRepository repository;
+
+    /** The configured class path. */
+    private String classPath;
+
+    @Reference(policy=ReferencePolicy.DYNAMIC, cardinality=ReferenceCardinality.OPTIONAL_UNARY)
+    private MimeTypeService mimeTypeService;
+
+    @Reference
+    private DynamicClassLoaderManager dynamicClassLoaderManager;
+
+    /** Cached repository class loader. */
+    private volatile RepositoryClassLoader repositoryClassLoader;
+
+    /**
+     * Activate this component.
+     * @param props The configuration properties
+     */
+    @Activate
+    protected void activate(final Map<String, Object> properties) {
+        Object prop = properties.get(CLASS_PATH_PROP);
+        if ( prop instanceof String[] && ((String[])prop).length > 0 ) {
+            this.classPath = ((String[])prop)[0];
+        } else {
+            this.classPath = CLASS_PATH_DEFAULT;
+        }
+        if ( this.classPath.endsWith("/") ) {
+            this.classPath = this.classPath.substring(0, this.classPath.length() - 1);
+        }
+
+        prop = properties.get(OWNER_PROP);
+        this.classLoaderOwner = (prop instanceof String)? (String) prop : OWNER_DEFAULT;
+    }
+
+    /**
+     * Deactivate this component.
+     */
+    @Deactivate
+    protected void deactivate() {
+        if ( this.repositoryClassLoader != null ) {
+            this.repositoryClassLoader.destroy();
+            this.repositoryClassLoader = null;
+        }
+    }
+
+    /**
+     * Return a new session.
+     */
+    private Session getSession() throws RepositoryException {
+        // get an administrative session for potentiall impersonation
+        final Session admin = this.repository.loginAdministrative(null);
+
+        // do use the admin session, if the admin's user id is the same as owner
+        if (admin.getUserID().equals(this.classLoaderOwner)) {
+            return admin;
+        }
+
+        // else impersonate as the owner and logout the admin session again
+        try {
+            return admin.impersonate(new SimpleCredentials(this.classLoaderOwner, new char[0]));
+        } finally {
+            admin.logout();
+        }
+    }
+
+    private synchronized ClassLoader getOrCreateClassLoader() {
+        if ( this.repositoryClassLoader == null || !this.repositoryClassLoader.isLive() ) {
+            if ( this.repositoryClassLoader != null ) {
+                this.repositoryClassLoader.destroy();
+            }
+            try {
+                this.repositoryClassLoader = new RepositoryClassLoader(
+                        this.getSession(),
+                        this.classPath,
+                        this.dynamicClassLoaderManager.getDynamicClassLoader());
+            } catch ( final RepositoryException re) {
+                throw new RuntimeException("Unable to instantiate repository class loader.", re);
+            }
+        }
+        return this.repositoryClassLoader;
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#delete(java.lang.String)
+     */
+    public boolean delete(final String name) {
+        final String path = cleanPath(name);
+        Session session = null;
+        try {
+            session = getSession();
+            if (session.itemExists(path)) {
+                Item fileItem = session.getItem(path);
+                fileItem.remove();
+                session.save();
+                this.repositoryClassLoader.handleEvent(path);
+                return true;
+            }
+        } catch (final RepositoryException re) {
+            logger.error("Cannot remove " + path, re);
+        } finally {
+            if ( session != null ) {
+                session.logout();
+            }
+        }
+
+        // fall back to false if item does not exist or in case of error
+        return false;
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getOutputStream(java.lang.String)
+     */
+    public OutputStream getOutputStream(final String name) {
+        final String path = cleanPath(name);
+        return new RepositoryOutputStream(this, path);
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#rename(java.lang.String, java.lang.String)
+     */
+    public boolean rename(final String oldName, final String newName) {
+        Session session = null;
+        try {
+            final String oldPath = cleanPath(oldName);
+            final String newPath = cleanPath(newName);
+
+            session = this.getSession();
+            session.move(oldPath, newPath);
+            session.save();
+            this.repositoryClassLoader.handleEvent(oldName);
+            this.repositoryClassLoader.handleEvent(newName);
+            return true;
+        } catch (final RepositoryException re) {
+            logger.error("Cannot rename " + oldName + " to " + newName, re);
+        } finally {
+            if ( session != null ) {
+                session.logout();
+            }
+        }
+
+        // fallback to false in case of error or non-existence of oldFileName
+        return false;
+    }
+
+    /**
+     * Creates a folder hierarchy in the repository.
+     * We synchronize this method to reduce potential conflics.
+     * Although each write uses its own session it might occur
+     * that more than one session tries to create the same path
+     * (or parent path) at the same time. By synchronizing this
+     * we avoid this situation - however this method is written
+     * in a failsafe manner anyway.
+     */
+    private synchronized boolean mkdirs(final Session session, final String path) {
+        try {
+            // quick test
+            if (session.itemExists(path) && session.getItem(path).isNode()) {
+                return true;
+            }
+
+            // check path walking it down
+            Node current = session.getRootNode();
+            final String[] names = path.split("/");
+            for (int i = 0; i < names.length; i++) {
+                if (names[i] == null || names[i].length() == 0) {
+                    continue;
+                } else if (current.hasNode(names[i])) {
+                    current = current.getNode(names[i]);
+                } else {
+                    final Node parentNode = current;
+                    try {
+                        // adding the node could cause an exception
+                        // for example if another thread tries to
+                        // create the node "at the same time"
+                        current = parentNode.addNode(names[i], NT_FOLDER);
+                        session.save();
+                    } catch (RepositoryException re) {
+                        // let's first refresh the session
+                        // we don't catch an exception here, because if
+                        // session refresh fails, we might have a serious problem!
+                        session.refresh(false);
+                        // let's check if the node is available now
+                        if ( parentNode.hasNode(names[i]) ) {
+                            current = parentNode.getNode(names[i]);
+                        } else {
+                            // we try it one more time to create the node - and fail otherwise
+                            current = parentNode.addNode(names[i], NT_FOLDER);
+                            session.save();
+                        }
+                    }
+                }
+            }
+
+            return true;
+
+        } catch (final RepositoryException re) {
+            logger.error("Cannot create folder path:" + path, re);
+            // discard changes
+            try {
+                session.refresh(false);
+            } catch (final RepositoryException e) {
+                // we simply ignore this
+            }
+        }
+
+        // false in case of error or no need to create
+        return false;
+    }
+
+    /**
+     * Helper method to clean the path.
+     * It replaces backslashes with slashes and cuts off trailing spaces.
+     * It uses the first configured class path to access the path.
+     */
+    private String cleanPath(String path) {
+        // replace backslash by slash
+        path = path.replace('\\', '/');
+
+        // cut off trailing slash
+        while (path.endsWith("/")) {
+            path = path.substring(0, path.length() - 1);
+        }
+
+        return this.classPath + path;
+    }
+
+    private static class RepositoryOutputStream extends ByteArrayOutputStream {
+
+        private final ClassLoaderWriterImpl repositoryOutputProvider;
+
+        private final String fileName;
+
+        RepositoryOutputStream(ClassLoaderWriterImpl repositoryOutputProvider,
+                String fileName) {
+            this.repositoryOutputProvider = repositoryOutputProvider;
+            this.fileName = fileName;
+        }
+
+        /**
+         * @see java.io.ByteArrayOutputStream#close()
+         */
+        public void close() throws IOException {
+            super.close();
+
+            Session session = null;
+            try {
+                // get an own session for writing
+                session = repositoryOutputProvider.getSession();
+                final int lastPos = fileName.lastIndexOf('/');
+                final String path = (lastPos == -1 ? null : fileName.substring(0, lastPos));
+                final String name = (lastPos == -1 ? fileName : fileName.substring(lastPos + 1));
+                if ( lastPos != -1 ) {
+                    if ( !repositoryOutputProvider.mkdirs(session, path) ) {
+                        throw new IOException("Unable to create path for " + path);
+                    }
+                }
+                Node fileNode = null;
+                Node contentNode = null;
+                Node parentNode = null;
+                if (session.itemExists(fileName)) {
+                    final Item item = session.getItem(fileName);
+                    if (item.isNode()) {
+                        final Node node = item.isNode() ? (Node) item : item.getParent();
+                        if ("jcr:content".equals(node.getName())) {
+                            // replace the content properties of the jcr:content
+                            // node
+                            parentNode = node;
+                            contentNode = node;
+                        } else if (node.isNodeType("nt:file")) {
+                            // try to set the content properties of jcr:content
+                            // node
+                            parentNode = node;
+                            contentNode = node.getNode("jcr:content");
+                        } else { // fileName is a node
+                            // try to set the content properties of the node
+                            parentNode = node;
+                            contentNode = node;
+                        }
+                    } else {
+                        // replace property with an nt:file node (if possible)
+                        parentNode = item.getParent();
+                        item.remove();
+                        session.save();
+                        fileNode = parentNode.addNode(name, "nt:file");
+                    }
+                } else {
+                    if (lastPos <= 0) {
+                        parentNode = session.getRootNode();
+                    } else {
+                        Item parent = session.getItem(path);
+                        if (!parent.isNode()) {
+                            throw new IOException("Parent at " + path + " is not a node.");
+                        }
+                        parentNode = (Node) parent;
+                    }
+                    fileNode = parentNode.addNode(name, "nt:file");
+                }
+
+                // if we have a file node, create the contentNode
+                if (fileNode != null) {
+                    contentNode = fileNode.addNode("jcr:content", "nt:resource");
+                }
+
+                final MimeTypeService mtService = this.repositoryOutputProvider.mimeTypeService;
+
+                String mimeType = (mtService == null ? null : mtService.getMimeType(fileName));
+                if (mimeType == null) {
+                    mimeType = "application/octet-stream";
+                }
+
+                contentNode.setProperty("jcr:lastModified", System.currentTimeMillis());
+                contentNode.setProperty("jcr:data", new ByteArrayInputStream(buf, 0, size()));
+                contentNode.setProperty("jcr:mimeType", mimeType);
+
+                session.save();
+                this.repositoryOutputProvider.repositoryClassLoader.handleEvent(fileName);
+            } catch (final RepositoryException re) {
+                throw (IOException)new IOException("Cannot write file " + fileName + ", reason: " + re.toString()).initCause(re);
+            } finally {
+                if ( session != null ) {
+                    session.logout();
+                }
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getInputStream(java.lang.String)
+     */
+    public InputStream getInputStream(final String name)
+    throws IOException {
+        final String path = cleanPath(name) + "/jcr:content/jcr:data";
+        Session session = null;
+        try {
+            session = this.getSession();
+            if ( session.itemExists(path) ) {
+                final Property prop = (Property)session.getItem(path);
+                return prop.getStream();
+            }
+            throw new FileNotFoundException("Unable to find " + name);
+        } catch (final RepositoryException re) {
+            throw (IOException) new IOException(
+                        "Failed to get InputStream for " + name).initCause(re);
+        } finally {
+            if ( session != null ) {
+                session.logout();
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getLastModified(java.lang.String)
+     */
+    public long getLastModified(final String name) {
+        final String path = cleanPath(name) + "/jcr:content/jcr:lastModified";
+        Session session = null;
+        try {
+            session = this.getSession();
+            if ( session.itemExists(path) ) {
+                final Property prop = (Property)session.getItem(path);
+                return prop.getLong();
+            }
+        } catch (final RepositoryException se) {
+            logger.error("Cannot get last modification time for " + name, se);
+        } finally {
+            if ( session != null ) {
+                session.logout();
+            }
+        }
+
+        // fallback to "non-existant" in case of problems
+        return -1;
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getClassLoader()
+     */
+    public ClassLoader getClassLoader() {
+        return this.getOrCreateClassLoader();
+    }
+}

Propchange: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java?rev=1304391&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java (added)
+++ sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java Fri Mar 23 14:53:38 2012
@@ -0,0 +1,495 @@
+/*
+ * 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.jcr.classloader.internal;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+
+import org.apache.sling.commons.classloader.DynamicClassLoader;
+import org.apache.sling.jcr.classloader.internal.net.URLFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The <code>RepositoryClassLoader</code> class provides the
+ * functionality to load classes and resources from the JCR Repository.
+ * Additionally, this class supports the notion of getting 'dirty', which means,
+ * that if a resource loaded through this class loader has been modified in the
+ * repository, this class loader marks itself dirty, which flag can get
+ * retrieved.
+ */
+public final class RepositoryClassLoader
+    extends SecureClassLoader
+    implements EventListener, DynamicClassLoader {
+
+    /** Logger */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+    /** Set of loaded resources and classes. */
+    private final Set<String> usedResources = new HashSet<String>();
+
+    /**
+     * Flag indicating whether there are loaded classes which have later been
+     * expired (e.g. invalidated or modified)
+     */
+    private boolean dirty = false;
+
+    /**
+     * The path to use as a classpath.
+     */
+    private String repositoryPath;
+
+    /**
+     * The <code>Session</code> grants access to the Repository to access the
+     * resources.
+     * <p>
+     * This field is not final such that it may be cleared when the class loader
+     * is destroyed.
+     */
+    private Session session;
+
+    /**
+     * Flag indicating whether the {@link #destroy()} method has already been
+     * called (<code>true</code>) or not (<code>false</code>)
+     */
+    private boolean destroyed = false;
+
+    /**
+     * Creates a <code>DynamicRepositoryClassLoader</code> from a list of item
+     * path strings containing globbing pattens for the paths defining the
+     * class path.
+     *
+     * @param session The <code>Session</code> to use to access the class items.
+     * @param classPath The list of path strings making up the (initial) class
+     *      path of this class loader. The strings may contain globbing
+     *      characters which will be resolved to build the actual class path.
+     * @param parent The parent <code>ClassLoader</code>, which may be
+     *      <code>null</code>.
+     *
+     * @throws NullPointerException if either the session or the classPath
+     *      is <code>null</code>.
+     */
+    public RepositoryClassLoader(final Session session,
+                                 final String classPath,
+                                 final ClassLoader parent) {
+        // initialize the super class with an empty class path
+        super(parent);
+
+        // check session and handles
+        if (session == null) {
+            throw new NullPointerException("session");
+        }
+        if (classPath == null) {
+            throw new NullPointerException("classPath");
+        }
+
+        // set fields
+        this.session = session;
+        this.repositoryPath = classPath;
+
+        // register with observation service and path pattern list
+        registerListener();
+
+        logger.debug("RepositoryClassLoader: {} ready", this);
+    }
+
+    /**
+     * Destroys this class loader. This process encompasses all steps needed
+     * to remove as much references to this class loader as possible.
+     * <p>
+     * <em>NOTE</em>: This method just clears all internal fields and especially
+     * the class path to render this class loader unusable.
+     * <p>
+     * This implementation does not throw any exceptions.
+     */
+    public void destroy() {
+        // we expect to be called only once, so we stop destroyal here
+        if (destroyed) {
+            logger.debug("Instance is already destroyed");
+            return;
+        }
+
+        // set destroyal guard
+        destroyed = true;
+
+        // remove ourselves as listeners from other places
+        unregisterListener();
+
+        // close session
+        if ( session != null ) {
+            session.logout();
+            session = null;
+        }
+        repositoryPath = null;
+        synchronized ( this.usedResources ) {
+            this.usedResources.clear();
+        }
+    }
+
+    /**
+     * 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 {
+        if (destroyed) {
+            throw new ClassNotFoundException(name + " (Classloader destroyed)");
+        }
+
+        logger.debug("findClass: Try to find class {}", name);
+
+        try {
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Class<?>>() {
+
+                    public Class<?> run() throws ClassNotFoundException {
+                        return findClassPrivileged(name);
+                    }
+                });
+        } catch (java.security.PrivilegedActionException pae) {
+            throw (ClassNotFoundException) pae.getException();
+        }
+    }
+
+    /**
+     * Finds the resource with the specified name on the search path.
+     *
+     * @param name the name of the resource
+     *
+     * @return a <code>URL</code> for the resource, or <code>null</code>
+     *      if the resource could not be found or if the class loader has
+     *      already been destroyed.
+     */
+    public URL findResource(final String name) {
+        if (destroyed) {
+            logger.warn("Destroyed class loader cannot find a resource");
+            return null;
+        }
+
+        logger.debug("findResource: Try to find resource {}", name);
+
+        final Node res = findClassLoaderResource(name);
+        if (res != null) {
+            logger.debug("findResource: Getting resource from {}",
+                res);
+            try {
+                return URLFactory.createURL(session, res.getPath());
+            } catch (Exception e) {
+                logger.warn("findResource: Cannot getURL for " + name, e);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an Enumeration of URLs representing all of the resources
+     * on the search path having the specified name.
+     *
+     * @param name the resource name
+     *
+     * @return an <code>Enumeration</code> of <code>URL</code>s. This is an
+     *      empty enumeration if no resources are found by this class loader
+     *      or if this class loader has already been destroyed.
+     */
+    public Enumeration<URL> findResources(final String name) {
+        if (destroyed) {
+            logger.warn("Destroyed class loader cannot find resources");
+            return new Enumeration<URL>() {
+                public boolean hasMoreElements() {
+                    return false;
+                }
+                public URL nextElement() {
+                    throw new NoSuchElementException("No Entries");
+                }
+            };
+        }
+
+        logger.debug("findResources: Try to find resources for {}", name);
+
+        final URL url = this.findResource(name);
+        final List<URL> list = new LinkedList<URL>();
+        if (url != null) {
+            list.add(url);
+        }
+
+        // return the enumeration on the list
+        return Collections.enumeration(list);
+    }
+
+    /**
+     * 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
+        logger.debug("findClassPrivileged: Try to find path {class {}",
+            name);
+
+        final Node res = this.findClassLoaderResource(name);
+        if (res != null) {
+
+             // try defining the class, error aborts
+             try {
+                 logger.debug(
+                    "findClassPrivileged: Loading class from {}", res);
+
+                 final Class<?> c = defineClass(name, res);
+                 if (c == null) {
+                     logger.warn("defineClass returned null for class {}", name);
+                     throw new ClassNotFoundException(name);
+                 }
+                 return c;
+
+             } catch (final IOException ioe) {
+                 logger.debug("defineClass failed", ioe);
+                 throw new ClassNotFoundException(name, ioe);
+             } catch (final Throwable t) {
+                 logger.debug("defineClass failed", t);
+                 throw new ClassNotFoundException(name, t);
+             }
+         }
+
+        throw new ClassNotFoundException(name);
+     }
+
+    /**
+     * Returns a {@link ClassLoaderResource} for the given <code>name</code> or
+     * <code>null</code> if not existing. If the resource has already been
+     * loaded earlier, the cached instance is returned. If the resource has
+     * not been found in an earlier call to this method, <code>null</code> is
+     * returned. Otherwise the resource is looked up in the class path. If
+     * found, the resource is cached and returned. If not found, the
+     * {@link #NOT_FOUND_RESOURCE} is cached for the name and <code>null</code>
+     * is returned.
+     *
+     * @param name The name of the resource to return.
+     *
+     * @return The named <code>ClassLoaderResource</code> if found or
+     *      <code>null</code> if not found.
+     *
+     * @throws NullPointerException If this class loader has already been
+     *      destroyed.
+     */
+    private Node findClassLoaderResource(final String name) {
+        final String path = this.repositoryPath + '/' + name.replace('.', '/') + (".class");
+        Node res = null;
+        try {
+            if ( session.itemExists(path) ) {
+                final Node node = (Node)session.getItem(path);
+                logger.debug("Found resource at {}", path);
+                synchronized ( this.usedResources ) {
+                    this.usedResources.add(path);
+                }
+                res = node;
+            } else {
+                logger.debug("No classpath entry contains {}", path);
+            }
+        } catch (final RepositoryException re) {
+            logger.debug("Error while trying to get node at " + path, re);
+        }
+        return res;
+    }
+
+    /**
+     * Defines a class getting the bytes for the class from the resource
+     *
+     * @param name The fully qualified class name
+     * @param res The resource to obtain the class bytes from
+     *
+     * @throws RepositoryException If a problem occurrs getting at the data.
+     * @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 Node res)
+    throws IOException, RepositoryException {
+        logger.debug("defineClass({}, {})", name, res);
+
+        final byte[] data = Util.getBytes(res);
+        final Class<?> clazz = defineClass(name, data, 0, data.length);
+
+        return clazz;
+    }
+
+    /**
+     * Returns whether the class loader is dirty. This can be the case if any
+     * of the loaded class has been expired through the observation.
+     * <p>
+     * This method may also return <code>true</code> if the <code>Session</code>
+     * associated with this class loader is not valid anymore.
+     * <p>
+     * Finally the method always returns <code>true</code> if the class loader
+     * has already been destroyed.
+     * <p>
+     *
+     * @return <code>true</code> if the class loader is dirty and needs
+     *      recreation.
+     */
+    public boolean isDirty() {
+        return destroyed || dirty || !session.isLive();
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.DynamicClassLoader#isLive()
+     */
+    public boolean isLive() {
+        return !this.isDirty();
+    }
+
+    //---------- EventListener interface -------------------------------
+
+    /**
+     * Handles a repository item modifcation events checking whether a class
+     * needs to be expired. As a side effect, this method sets the class loader
+     * dirty if a loaded class has been modified in the repository.
+     *
+     * @param events The iterator of repository events to be handled.
+     */
+    public void onEvent(final EventIterator events) {
+        while (events.hasNext()) {
+            final Event event = events.nextEvent();
+            String path;
+            try {
+                path = event.getPath();
+            } catch (RepositoryException re) {
+                logger.warn("onEvent: Cannot get path of event, ignoring", re);
+                continue;
+            }
+
+            if ( event.getType() == Event.PROPERTY_ADDED || event.getType() == Event.PROPERTY_CHANGED || event.getType() == Event.PROPERTY_REMOVED ) {
+                final int lastSlash = path.lastIndexOf('/');
+                path = path.substring(0, lastSlash);
+            }
+            if ( path.endsWith("/jcr:content") ) {
+                path = path.substring(0, path.length() - 12);
+            }
+            this.handleEvent(path);
+        }
+    }
+
+    /**
+     * Handle a modification event.
+     */
+    public void handleEvent(final String path) {
+        synchronized ( this.usedResources ) {
+            if ( this.usedResources.contains(path) ) {
+                logger.debug("handleEvent: Item {} has been modified - marking class loader as dirty {}", this);
+                this.dirty = true;
+            }
+        }
+
+    }
+    //----------- Object overwrite ---------------------------------------------
+
+    /**
+     * Returns a string representation of this class loader.
+     */
+    public String toString() {
+        StringBuilder buf = new StringBuilder(getClass().getName());
+        if (destroyed) {
+            buf.append(" - destroyed");
+        } else {
+            buf.append(": parent: { ");
+            buf.append(getParent());
+            buf.append(" }, user: ");
+            buf.append(session.getUserID());
+            buf.append(", dirty: ");
+            buf.append(isDirty());
+        }
+        return buf.toString();
+    }
+
+    //---------- internal ------------------------------------------------------
+
+    /**
+     * Registers this class loader with the observation service to get
+     * information on page updates in the class path and to the path
+     * pattern list to get class path updates.
+     *
+     * @throws NullPointerException if this class loader has already been
+     *      destroyed.
+     */
+    private final void registerListener() {
+        logger.debug("registerListener: Registering to the observation service");
+
+        try {
+            final ObservationManager om = session.getWorkspace().getObservationManager();
+            om.addEventListener(this,
+                    Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED,
+                    repositoryPath, true, null, null, false);
+        } catch (final RepositoryException re) {
+            logger.error("registerModificationListener: Cannot register " +
+                this + " with observation manager", re);
+        }
+    }
+
+    /**
+     * Removes this instances registrations from the observation service and
+     * the path pattern list.
+     *
+     * @throws NullPointerException if this class loader has already been
+     *      destroyed.
+     */
+    private final void unregisterListener() {
+        logger.debug("unregisterListener: Deregistering from the observation service");
+        // check session first!
+        if ( session.isLive() ) {
+            try {
+                final ObservationManager om = session.getWorkspace().getObservationManager();
+                om.removeEventListener(this);
+            } catch (RepositoryException re) {
+                logger.error("unregisterListener: Cannot unregister " +
+                    this + " from observation manager", re);
+            }
+        }
+    }
+}

Propchange: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/Util.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/Util.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/Util.java (original)
+++ sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/Util.java Fri Mar 23 14:53:38 2012
@@ -16,11 +16,13 @@
  */
 package org.apache.sling.jcr.classloader.internal;
 
-import javax.jcr.AccessDeniedException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
 import javax.jcr.Item;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -67,7 +69,7 @@ public class Util {
      * returned. Otherwise if the resulting property is a <code>REFERENCE</code>
      * property, the node referred to is retrieved and this method is called
      * recursively with the node. Otherwise, the resulting property is returned.
-     * 
+     *
      * @param item The <code>Item</code> to resolve to a <code>Property</code>.
      * @return The resolved <code>Property</code> or <code>null</code> if
      *         the resolved property is a multi-valued property or the
@@ -93,7 +95,7 @@ public class Util {
 
             // if the node has a jcr:data property, use that property
             if (node.hasProperty("jcr:data")) {
-                
+
                 prop = node.getProperty("jcr:data");
 
             } else {
@@ -135,32 +137,28 @@ public class Util {
     }
 
     /**
-     * Returns the last modification time of the property, which is the long
-     * value of the <code>jcr:lastModified</code> property of the parent node
-     * of <code>prop</code>. If the parent node does not have a
-     * <code>jcr:lastModified</code> property the current system time is
-     * returned.
-     * 
-     * @param prop The property for which to return the last modification time.
-     * @return The last modification time of the resource or the current time if
-     *         the parent node of the property does not have a
-     *         <code>jcr:lastModified</code> property.
-     * @throws ItemNotFoundException If the parent node of the property cannot
-     *             be retrieved.
-     * @throws AccessDeniedException If (read) access to the parent node is
-     *             denied.
-     * @throws RepositoryException If any other error occurrs accessing the
-     *             repository to retrieve the last modification time.
+     * Returns the resource as an array of bytes
      */
-    public static long getLastModificationTime(Property prop)
-            throws ItemNotFoundException, PathNotFoundException,
-            AccessDeniedException, RepositoryException {
-
-        Node parent = prop.getParent();
-        if (parent.hasProperty("jcr:lastModified")) {
-            return parent.getProperty("jcr:lastModified").getLong();
-        }
+    public static byte[] getBytes(final Node node) throws IOException, RepositoryException {
+        InputStream in = null;
 
-        return System.currentTimeMillis();
+        try {
+            in = getProperty(node).getStream();
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            final byte[] buffer = new byte[2048];
+            int l = 0;
+            while ( (l = in.read(buffer)) > -1 ) {
+                baos.write(buffer, 0, l);
+            }
+            return baos.toByteArray();
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (final IOException ignore) {
+                    // ignore
+                }
+            }
+        }
     }
 }

Modified: sling/trunk/bundles/scripting/jsp/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/pom.xml?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/pom.xml (original)
+++ sling/trunk/bundles/scripting/jsp/pom.xml Fri Mar 23 14:53:38 2012
@@ -119,7 +119,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.classloader</artifactId>
-            <version>1.2.0</version>
+            <version>1.2.5-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
 

Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java (original)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java Fri Mar 23 14:53:38 2012
@@ -46,7 +46,6 @@ import org.apache.sling.api.scripting.Sl
 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.scripting.api.AbstractScriptEngineFactory;
 import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
 import org.apache.sling.scripting.jsp.jasper.JasperException;
@@ -93,14 +92,8 @@ public class JspScriptEngineFactory
     private ServletContext slingServletContext;
 
     @Reference
-    private DynamicClassLoaderManager dynamicClassLoaderManager;
-
-    @Reference
     private ClassLoaderWriter classLoaderWriter;
 
-    /** The class loader for the jsps. */
-    private ClassLoader jspClassLoader;
-
     /** The io provider for reading and writing. */
     private SlingIOProvider ioProvider;
 
@@ -284,7 +277,7 @@ public class JspScriptEngineFactory
         // set the current class loader as the thread context loader for
         // the setup of the JspRuntimeContext
         final ClassLoader old = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader(jspClassLoader);
+        Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
 
         try {
             this.jspFactoryHandler = JspRuntimeContext.initFactoryHandler();
@@ -296,14 +289,11 @@ public class JspScriptEngineFactory
 
             // return options which use the jspClassLoader
             options = new JspServletOptions(slingServletContext, ioProvider,
-                componentContext, jspClassLoader, tldLocationsCache);
+                componentContext, tldLocationsCache);
 
             // Initialize the JSP Runtime Context
             this.jspRuntimeContext = new JspRuntimeContext(slingServletContext,
-                    options);
-
-                // by default access the repository
-            this.jspRuntimeContext.setIOProvider(ioProvider);
+                    options, ioProvider);
 
             jspServletContext = new JspServletContext(ioProvider,
                 slingServletContext, tldLocationsCache);
@@ -392,44 +382,6 @@ public class JspScriptEngineFactory
         }
     }
 
-    /**
-     * Bind the class load provider.
-     *
-     * @param repositoryClassLoaderProvider the new provider
-     */
-    protected void bindDynamicClassLoaderManager(final DynamicClassLoaderManager rclp) {
-        if ( this.jspClassLoader != null ) {
-            this.ungetClassLoader();
-        }
-        this.getClassLoader(rclp);
-    }
-
-    /**
-     * Unbind the class loader provider.
-     * @param repositoryClassLoaderProvider the old provider
-     */
-    protected void unbindDynamicClassLoaderManager(final DynamicClassLoaderManager rclp) {
-        if ( this.dynamicClassLoaderManager == rclp ) {
-            this.ungetClassLoader();
-        }
-    }
-
-    /**
-     * Get the class loader
-     */
-    private void getClassLoader(final DynamicClassLoaderManager rclp) {
-        this.dynamicClassLoaderManager = rclp;
-        this.jspClassLoader = rclp.getDynamicClassLoader();
-    }
-
-    /**
-     * Unget the class loader
-     */
-    private void ungetClassLoader() {
-        this.jspClassLoader = null;
-        this.dynamicClassLoaderManager = null;
-    }
-
     // ---------- Internal -----------------------------------------------------
 
     private class JspScriptEngine extends AbstractSlingScriptEngine {
@@ -447,11 +399,11 @@ public class JspScriptEngineFactory
                 // set the current class loader as the thread context loader for
                 // the compilation and execution of the JSP script
                 ClassLoader old = Thread.currentThread().getContextClassLoader();
-                Thread.currentThread().setContextClassLoader(jspClassLoader);
+                Thread.currentThread().setContextClassLoader(classLoaderWriter.getClassLoader());
 
                 try {
                     callJsp(props, scriptHelper, context);
-                } catch (SlingServletException e) {
+                } catch (final SlingServletException e) {
                     // ServletExceptions use getRootCause() instead of getCause(),
                     // so we have to extract the actual root cause and pass it as
                     // cause in our new ScriptException
@@ -472,7 +424,7 @@ public class JspScriptEngineFactory
                 } catch (final SlingPageException sje) {
                 	callErrorPageJsp(props, scriptHelper, context, sje.getErrorPage());
 
-                } catch (Exception e) {
+                } catch (final Exception e) {
 
                     throw new BetterScriptException(e.getMessage(), e);
 

Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspServletOptions.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspServletOptions.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspServletOptions.java (original)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspServletOptions.java Fri Mar 23 14:53:38 2012
@@ -109,11 +109,6 @@ public class JspServletOptions implement
     private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
 
     /**
-     * What classpath should I use while compiling generated servlets?
-     */
-    private String classpath;
-
-    /**
      * Compiler target VM.
      */
     private String compilerTargetVM = DEFAULT_VM_VERSION;
@@ -144,11 +139,6 @@ public class JspServletOptions implement
     private String javaEncoding = "UTF8";
 
     /**
-     * The class loader to use to compile and load JSP files
-     */
-    private ClassLoader jspClassLoader;
-
-    /**
      * Is generation of X-Powered-By response header enabled/disabled?
      */
     private boolean xpoweredBy;
@@ -237,21 +227,6 @@ public class JspServletOptions implement
     }
 
     /**
-     * What classpath should I use while compiling the servlets generated from
-     * JSP files?
-     */
-    public String getClassPath() {
-        return this.classpath;
-    }
-
-    /**
-     * Return <code>null</code> to force use of the <code>JasperLoader</code>.
-     */
-    public ClassLoader getJspClassLoader() {
-        return this.jspClassLoader;
-    }
-
-    /**
      * Is generation of X-Powered-By response header enabled/disabled?
      */
     public boolean isXpoweredBy() {
@@ -330,9 +305,7 @@ public class JspServletOptions implement
      */
     public JspServletOptions(ServletContext servletContext,
             IOProvider ioProvider, ComponentContext componentContext,
-            ClassLoader jspClassLoader, TldLocationsCache tldLocationsCache) {
-
-        this.jspClassLoader = jspClassLoader;
+            TldLocationsCache tldLocationsCache) {
 
         // JVM version numbers default to 1.5
         this.compilerSourceVM = DEFAULT_VM_VERSION;
@@ -504,11 +477,6 @@ public class JspServletOptions implement
             this.ieClassId = ieClassId;
         }
 
-        String classpath = getProperty("classpath");
-        if (classpath != null) {
-            this.classpath = classpath;
-        }
-
         String compilerTargetVM = getProperty("compilerTargetVM");
         if (compilerTargetVM != null) {
             this.compilerTargetVM = compilerTargetVM;

Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/SlingIOProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/SlingIOProvider.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/SlingIOProvider.java (original)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/SlingIOProvider.java Fri Mar 23 14:53:38 2012
@@ -149,8 +149,16 @@ class SlingIOProvider implements IOProvi
         return true;
     }
 
+    /**
+     * @see org.apache.sling.scripting.jsp.jasper.IOProvider#getClassLoader()
+     */
+    public ClassLoader getClassLoader() {
+        return this.classLoaderWriter.getClassLoader();
+    }
+
     // ---------- Helper Methods for JspServletContext -------------------------
 
+
     /* package */URL getURL(String path) throws MalformedURLException {
         try {
             Resource resource = getResourceInternal(path);

Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IOProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IOProvider.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IOProvider.java (original)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IOProvider.java Fri Mar 23 14:53:38 2012
@@ -15,10 +15,7 @@
  */
 package org.apache.sling.scripting.jsp.jasper;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -31,35 +28,6 @@ import java.io.OutputStream;
 public interface IOProvider {
 
     /**
-     * The default output provider, which is based on the OS filesystem
-     */
-    public static final IOProvider DEFAULT = new IOProvider() {
-        public OutputStream getOutputStream(String fileName) throws IOException {
-            File file = new File(fileName);
-            file.getParentFile().mkdirs(); // ensure parent path exists
-            return new FileOutputStream(fileName);
-        }
-        public InputStream getInputStream(String fileName)
-                throws FileNotFoundException, IOException {
-            return new FileInputStream(fileName);
-        }
-        public boolean delete(String fileName) {
-            return new File(fileName).delete();
-        }
-        public boolean rename(String oldFileName, String newFileName) {
-            return new File(oldFileName).renameTo(new File(newFileName));
-        }
-        public boolean mkdirs(String path) {
-            File dirFile = new File(path);
-            return dirFile.isDirectory() || dirFile.mkdirs();
-        }
-        public long lastModified(String path) {
-            File checkFile = new File(path);
-            return (checkFile.exists()) ? checkFile.lastModified() : -1L;
-        }
-    };
-
-    /**
      * @param fileName The absolute path name of the destination into which to
      *      write the output. The semantics of this path depends on the
      *      implementation of this interface.
@@ -133,4 +101,9 @@ public interface IOProvider {
      *      since the epoch or -1 if no resource exists at the given location.
      */
     long lastModified(String fileName);
+
+    /**
+     * Return the class loader to use
+     */
+    ClassLoader getClassLoader();
 }

Added: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java?rev=1304391&view=auto
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java (added)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java Fri Mar 23 14:53:38 2012
@@ -0,0 +1,160 @@
+/*
+ * 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.jsp.jasper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+
+
+/**
+ * The <code>IsolatedClassLoader</code> class loads classes through
+ * the class loader writer
+ */
+public final class IsolatedClassLoader
+    extends SecureClassLoader {
+
+    private final IOProvider ioProvider;
+
+    public IsolatedClassLoader(final ClassLoader parent,
+            final IOProvider ioProvider) {
+        super(parent);
+        this.ioProvider = ioProvider;
+    }
+
+
+    //---------- 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.ioProvider.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);
+    }
+}

Propchange: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java (original)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java Fri Mar 23 14:53:38 2012
@@ -139,42 +139,12 @@ public class JspCompilationContext {
         }
     }
 
-    /* ==================== Methods to override ==================== */
-
-    /** ---------- Class path and loader ---------- */
-
-    /**
-     * The classpath that is passed off to the Java compiler.
-    public String getClassPath() {
-        if( classPath != null )
-            return classPath;
-        return rctxt.getClassPath();
-    }
-     */
-
-    /**
-     * The classpath that is passed off to the Java compiler.
-    public void setClassPath(String classPath) {
-        this.classPath = classPath;
-    }
-     */
-
     /**
      * What class loader to use for loading classes while compiling
      * this JSP?
      */
     public ClassLoader getClassLoader() {
-        return getJspLoader();
-    }
-
-    /**
-    public void setClassLoader(ClassLoader loader) {
-        this.loader = loader;
-    }
-     */
-
-    public ClassLoader getJspLoader() {
-        return options.getJspClassLoader();
+        return getRuntimeContext().getIOProvider().getClassLoader();
     }
 
     /** ---------- Input/Output  ---------- */
@@ -628,15 +598,13 @@ public class JspCompilationContext {
         throws JasperException, FileNotFoundException
     {
         try {
-            getJspLoader();
-
             String name;
             if (isTagFile()) {
                 name = tagInfo.getTagClassName();
             } else {
                 name = getServletPackageName() + "." + getServletClassName();
             }
-            servletClass = getJspLoader().loadClass(name);
+            servletClass = getClassLoader().loadClass(name);
         } catch (ClassNotFoundException cex) {
             throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
                                       cex);

Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/Options.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/Options.java?rev=1304391&r1=1304390&r2=1304391&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/Options.java (original)
+++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/Options.java Fri Mar 23 14:53:38 2012
@@ -96,24 +96,6 @@ public interface Options {
     public String getScratchDir();
 
     /**
-     * What classpath should I use while compiling the servlets
-     * generated from JSP files?
-     */
-    public String getClassPath();
-
-    /**
-     * The classloader to use when compiling servlets generated from JSP files
-     * and to load the servlets.
-     * <p>
-     * If this method returns <code>null</code> the
-     * {@link org.apache.sling.scripting.jsp.jasper.servlet.JasperLoader} class is used.
-     *
-     * @return The <code>ClassLoader</code> to use for compilation and JSP
-     *      loading or <code>null</code> to use the <code>JasperLoader</code>.
-     */
-    public ClassLoader getJspClassLoader();
-
-    /**
      * Compiler to use.
      */
     public String getCompiler();



Mime
View raw message