You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2009/10/12 10:53:34 UTC

svn commit: r824266 - in /sling/trunk/bundles/jcr/classloader: ./ src/main/java/org/apache/sling/jcr/classloader/internal/ src/main/resources/OSGI-INF/metatype/

Author: cziegeler
Date: Mon Oct 12 08:53:33 2009
New Revision: 824266

URL: http://svn.apache.org/viewvc?rev=824266&view=rev
Log:
SLING-1150 : Session is not closed in getLastModified
SLING-1146 : DynamicClassLoaderProvider and ClassLoaderWriter should not be a service factory and refactored session handling
SLING-1151 : Don't export jackrabbit classes

Added:
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicClassLoaderProviderImpl.java   (with props)
Modified:
    sling/trunk/bundles/jcr/classloader/pom.xml
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java
    sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java
    sling/trunk/bundles/jcr/classloader/src/main/resources/OSGI-INF/metatype/metatype.properties

Modified: sling/trunk/bundles/jcr/classloader/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/pom.xml?rev=824266&r1=824265&r2=824266&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/classloader/pom.xml (original)
+++ sling/trunk/bundles/jcr/classloader/pom.xml Mon Oct 12 08:53:33 2009
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>6</version>
+        <version>7</version>
         <relativePath>../../../parent/pom.xml</relativePath>
     </parent>
 
@@ -59,14 +59,14 @@
                             sling,jcr,jackrabbit
                         </Bundle-Category>
                         <Export-Package>
-                            org.apache.sling.jcr.classloader;version=${pom.version},
-                            org.apache.jackrabbit.classloader;
-                            org.apache.jackrabbit.net;version=1.4
+                            org.apache.sling.jcr.classloader;version=${pom.version}
                         </Export-Package>
                         <Private-Package>
                             org.apache.sling.jcr.classloader.internal.*,
                             org.apache.jackrabbit;
+                            org.apache.jackrabbit.classloader;
                             org.apache.jackrabbit.name;
+                            org.apache.jackrabbit.net;
                             org.apache.jackrabbit.util;split-package:=merge-first
                         </Private-Package>
                     </instructions>
@@ -88,31 +88,38 @@
         </plugins>
     </reporting>
     <dependencies>
+       <dependency>
+           <groupId>javax.jcr</groupId>
+           <artifactId>jcr</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.jcr.api</artifactId>
             <version>2.0.2-incubator</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.classloader</artifactId>
             <version>0.9.0</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.mime</artifactId>
             <version>2.1.0-incubator</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.jackrabbit</groupId>
             <artifactId>jackrabbit-classloader</artifactId>
-            <version>1.4.1</version>
+            <version>1.5.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.jackrabbit</groupId>
             <artifactId>jackrabbit-jcr-commons</artifactId>
-            <version>1.4.2</version>
+            <version>1.6.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
@@ -127,13 +134,14 @@
             <groupId>commons-collections</groupId>
             <artifactId>commons-collections</artifactId>
             <version>3.2.1</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.felix</groupId>
+            <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.felix</groupId>
+            <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
         </dependency>
     </dependencies>

Added: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicClassLoaderProviderImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicClassLoaderProviderImpl.java?rev=824266&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicClassLoaderProviderImpl.java (added)
+++ sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/DynamicClassLoaderProviderImpl.java Mon Oct 12 08:53:33 2009
@@ -0,0 +1,458 @@
+/*
+ * 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.Dictionary;
+
+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.sling.commons.classloader.ClassLoaderWriter;
+import org.apache.sling.commons.classloader.DynamicClassLoaderProvider;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>DynamicClassLoaderProviderImpl</code> TODO
+ *
+ * @scr.component label="%loader.name"
+ *      description="%loader.description"
+ * @scr.property name="service.vendor" value="The Apache Software Foundation"
+ * @scr.property name="service.description"
+ *      value="Provides Repository ClassLoaders"
+ * @scr.service interface="DynamicClassLoaderProvider"
+ * @scr.service interface="ClassLoaderWriter"
+ */
+public class DynamicClassLoaderProviderImpl
+        implements DynamicClassLoaderProvider, ClassLoaderWriter {
+
+    /** default log */
+    private final Logger log = LoggerFactory.getLogger(RepositoryClassLoaderFacade.class);
+
+    /**
+     * @scr.property valueRefs0="CLASS_PATH_DEFAULT"
+     */
+    public static final String CLASS_PATH_PROP = "classpath";
+
+    public static final String CLASS_PATH_DEFAULT = "/var/classes";
+
+    /**
+     * @scr.property valueRef="OWNER_DEFAULT"
+     */
+    public static final String OWNER_PROP = "owner";
+
+    /** Default class loader owner. */
+    public static final String OWNER_DEFAULT = "admin";
+
+    /** The owner of the class loader / jcr user. */
+    private String classLoaderOwner;
+
+
+    /** JSP Class Loader class path will be injected to the class loader. */
+    private static final String[] CLASS_PATH_EMPTY = { };
+
+    /**
+     * @scr.reference
+     */
+    private SlingRepository repository;
+
+    private String[] classPath;
+
+    private RepositoryClassLoaderFacade facade;
+
+    /** @scr.reference policy="dynamic" */
+    private MimeTypeService mimeTypeService;
+
+    /** The read session. */
+    private Session readSession;
+
+    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.getOwnerId())) {
+            return admin;
+        }
+
+        // else impersonate as the owner and logout the admin session again
+        try {
+            return admin.impersonate(new SimpleCredentials(this.getOwnerId(), new char[0]));
+        } finally {
+            admin.logout();
+        }
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.DynamicClassLoaderProvider#getClassLoader(ClassLoader)
+     */
+    public ClassLoader getClassLoader(final ClassLoader parent) {
+        if ( this.facade == null ) {
+            this.facade = new RepositoryClassLoaderFacade(this, parent, this.getClassPaths());
+        }
+
+        return this.facade;
+    }
+
+    //---------- SCR Integration ----------------------------------------------
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#delete(java.lang.String)
+     */
+    public boolean delete(String name) {
+        name = cleanPath(name);
+        Node parentNode = null;
+        Session session = null;
+        try {
+            session = getSession();
+            if (session.itemExists(name)) {
+                Item fileItem = session.getItem(name);
+                parentNode = fileItem.getParent();
+                fileItem.remove();
+                parentNode.save();
+                return true;
+            }
+        } catch (RepositoryException re) {
+            log.error("Cannot remove " + name, re);
+        } finally {
+            checkNode(parentNode, name);
+            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(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(String oldName, String newName) {
+        Session session = null;
+        try {
+            oldName = cleanPath(oldName);
+            newName = cleanPath(newName);
+
+            session = this.getSession();
+            session.getWorkspace().move(oldName, newName);
+            return true;
+        } catch (RepositoryException re) {
+            log.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.
+     */
+    private boolean mkdirs(final Session session, String path) {
+        Node parentNode = null;
+        try {
+            // quick test
+            if (session.itemExists(path) && session.getItem(path).isNode()) {
+                return true;
+            }
+
+            // check path walking it down
+            Node current = session.getRootNode();
+            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 {
+                    if (parentNode == null) {
+                        parentNode = current;
+                    }
+                    current = current.addNode(names[i], "nt:folder");
+                }
+            }
+
+            if (parentNode != null) {
+                parentNode.save();
+                return true;
+            }
+
+        } catch (RepositoryException re) {
+            log.error("Cannot create folder path " + path, re);
+        } finally {
+            checkNode(parentNode, path);
+        }
+
+        // false in case of error or no need to create
+        return false;
+    }
+
+    private void checkNode(Node node, String path) {
+        if (node != null && node.isModified()) {
+            try {
+                node.refresh(false);
+            } catch (RepositoryException re) {
+                log.error("Cannot refresh node for " + path
+                    + " after failed save", re);
+            }
+        }
+    }
+
+    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);
+        }
+
+        if ( this.classPath == null || this.classPath.length == 0 ) {
+            return path;
+        }
+        return this.classPath[0] + path;
+    }
+
+    private static class RepositoryOutputStream extends ByteArrayOutputStream {
+
+        private final DynamicClassLoaderProviderImpl repositoryOutputProvider;
+
+        private final String fileName;
+
+        RepositoryOutputStream(DynamicClassLoaderProviderImpl repositoryOutputProvider,
+                String fileName) {
+            this.repositoryOutputProvider = repositoryOutputProvider;
+            this.fileName = fileName;
+        }
+
+        public void close() throws IOException {
+            super.close();
+
+            Node parentNode = null;
+            Session session = null;
+            try {
+                session = repositoryOutputProvider.getSession();
+                final int lastPos = fileName.lastIndexOf('/');
+                if ( lastPos != -1 ) {
+                    repositoryOutputProvider.mkdirs(session, fileName.substring(0, lastPos));
+                }
+                Node fileNode = null;
+                Node contentNode = null;
+                if (session.itemExists(fileName)) {
+                    Item item = session.getItem(fileName);
+                    if (item.isNode()) {
+                        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();
+                        String name = item.getName();
+                        fileNode = parentNode.addNode(name, "nt:file");
+                        item.remove();
+                    }
+                } else {
+                    int lastSlash = fileName.lastIndexOf('/');
+                    if (lastSlash <= 0) {
+                        parentNode = session.getRootNode();
+                    } else {
+                        Item parent = session.getItem(fileName.substring(0,
+                            lastSlash));
+                        if (!parent.isNode()) {
+                            // TODO: fail
+                        }
+                        parentNode = (Node) parent;
+                    }
+                    String name = fileName.substring(lastSlash + 1);
+                    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);
+
+                parentNode.save();
+            } catch (RepositoryException re) {
+                repositoryOutputProvider.log.error("Cannot write file " + fileName, re);
+                throw new IOException("Cannot write file " + fileName
+                    + ", reason: " + re.toString());
+            } finally {
+                repositoryOutputProvider.checkNode(parentNode, fileName);
+                if ( session != null ) {
+                    session.logout();
+                }
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getInputStream(java.lang.String)
+     */
+    public InputStream getInputStream(String fileName)
+    throws IOException {
+        final String path = cleanPath(fileName) + "/jcr:content/jcr:data";
+        Session session = null;
+        try {
+            session = this.getReadSession();
+            if ( session.itemExists(path) ) {
+                final Property prop = (Property)session.getItem(path);
+                return prop.getStream();
+            }
+            throw new FileNotFoundException("Unable to find " + fileName);
+        } catch (RepositoryException re) {
+            throw (IOException) new IOException(
+                        "Failed to get InputStream for " + fileName).initCause(re);
+        }
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getLastModified(java.lang.String)
+     */
+    public long getLastModified(String fileName) {
+        final String path = cleanPath(fileName) + "/jcr:content/jcr:lastModified";
+        Session session = null;
+        try {
+            session = this.getReadSession();
+            if ( session.itemExists(path) ) {
+                final Property prop = (Property)session.getItem(path);
+                return prop.getLong();
+            }
+        } catch (RepositoryException se) {
+            log.error("Cannot get last modification time for " + fileName, se);
+        }
+
+        // fallback to "non-existant" in case of problems
+        return -1;
+    }
+
+    /**
+     * Activate this component.
+     * @param componentContext
+     */
+    protected void activate(final ComponentContext componentContext) {
+        @SuppressWarnings("unchecked")
+        Dictionary properties = componentContext.getProperties();
+
+        Object prop = properties.get(CLASS_PATH_PROP);
+        this.classPath = (prop instanceof String[]) ? (String[]) prop : CLASS_PATH_EMPTY;
+
+        prop = properties.get(OWNER_PROP);
+        this.classLoaderOwner = (prop instanceof String)? (String) prop : OWNER_DEFAULT;
+    }
+
+    /**
+     * Deactivate this component
+     * @param componentContext
+     */
+    protected void deactivate(final ComponentContext componentContext) {
+        if ( this.facade != null) {
+            this.facade.destroy();
+            this.facade = null;
+        }
+        if ( this.readSession != null ) {
+            this.readSession.logout();
+            this.readSession = null;
+        }
+    }
+
+    /**
+     * Return the owner id
+     */
+    protected String getOwnerId() {
+        return this.classLoaderOwner;
+    }
+
+    /**
+     * Return the configured class paths
+     */
+    protected String[] getClassPaths() {
+        return this.classPath;
+    }
+
+    public synchronized Session getReadSession() throws RepositoryException {
+        // check current session
+        if (this.readSession != null) {
+            if (this.readSession.isLive()) {
+                return this.readSession;
+            }
+
+            // current session is not live anymore, drop
+            this.readSession.logout();
+            this.readSession = null;
+        }
+
+        // no session currently, acquire and return
+        this.readSession = this.getSession();
+        return this.readSession;
+    }
+}

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

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

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

Modified: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java?rev=824266&r1=824265&r2=824266&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java (original)
+++ sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java Mon Oct 12 08:53:33 2009
@@ -24,7 +24,6 @@
 import java.util.Enumeration;
 
 import javax.jcr.RepositoryException;
-import javax.jcr.Session;
 
 import org.apache.jackrabbit.classloader.DynamicRepositoryClassLoader;
 import org.slf4j.Logger;
@@ -36,21 +35,18 @@
 class RepositoryClassLoaderFacade extends URLClassLoader {
 
     /** default log */
-    private static final Logger log = LoggerFactory.getLogger(RepositoryClassLoaderFacade.class);
+    private final Logger log = LoggerFactory.getLogger(RepositoryClassLoaderFacade.class);
 
     private static final URL[] NO_URLS = new URL[0];
 
-    private RepositoryClassLoaderProviderImpl classLoaderProvider;
+    private DynamicClassLoaderProviderImpl classLoaderProvider;
     private ClassLoader parent;
-    private String sessionOwner;
-    private Session session;
     private String[] classPath;
     private DynamicRepositoryClassLoader delegate;
 
     public RepositoryClassLoaderFacade(
-            RepositoryClassLoaderProviderImpl classLoaderProvider,
+            DynamicClassLoaderProviderImpl classLoaderProvider,
             ClassLoader parent,
-            String sessionOwner,
             String[] classPath) {
 
         // no parent class loader, we delegate to repository class loaders
@@ -59,26 +55,6 @@
         this.classLoaderProvider = classLoaderProvider;
         this.parent = parent;
         this.classPath = classPath;
-        this.sessionOwner = sessionOwner;
-    }
-
-    public void addPath(String path) {
-        // create new class path
-        String[] newClassPath = new String[this.classPath.length+1];
-        System.arraycopy(this.classPath, 0, newClassPath, 0, this.classPath.length);
-        newClassPath[this.classPath.length] = path;
-        this.classPath = newClassPath;
-
-        // destroy the delegate and have a new one created
-        if (this.delegate != null) {
-            DynamicRepositoryClassLoader oldLoader = this.delegate;
-            this.delegate = null;
-            oldLoader.destroy();
-        }
-    }
-
-    public String[] getClassPath() {
-        return this.classPath.clone();
     }
 
     @Override
@@ -117,54 +93,25 @@
         }
     }
 
-    //---------- Reference counting support -----------------------------------
-
-    /* package */ void destroy() {
+    void destroy() {
         if (this.delegate != null) {
             this.delegate.destroy();
             this.delegate = null;
         }
-
-        if (this.session != null) {
-            this.session.logout();
-            this.session = null;
-        }
     }
 
     //---------- internal -----------------------------------------------------
 
-    private Session getSession() throws RepositoryException {
-        // check current session
-        if (this.session != null) {
-            if (this.session.isLive()) {
-                return this.session;
-            }
+    private synchronized DynamicRepositoryClassLoader getDelegateClassLoader() throws RepositoryException {
+        if ( this.delegate == null ) {
+            this.delegate = new DynamicRepositoryClassLoader( this.classLoaderProvider.getReadSession(), this.classPath, this.parent);
 
-            // drop delegate
-            if (this.delegate != null) {
-                this.delegate.destroy();
-                this.delegate = null;
-            }
-
-            // current session is not live anymore, drop
-            this.session.logout();
-            this.session = null;
-        }
-
-        // no session currently, acquire and return
-        this.session = this.classLoaderProvider.getSession(this.sessionOwner);
-        return this.session;
-    }
-
-    private DynamicRepositoryClassLoader getDelegateClassLoader() throws RepositoryException {
-        if (this.delegate != null) {
+        } else {
             if (this.delegate.isDirty()) {
-                this.delegate = this.delegate.reinstantiate(this.getSession(), this.parent);
+                this.delegate = this.delegate.reinstantiate(this.classLoaderProvider.getReadSession(), this.parent);
             }
-        } else {
-            this.delegate = new DynamicRepositoryClassLoader(this.getSession(), this.classPath, this.parent);
-        }
 
+        }
         return this.delegate;
     }
 

Modified: sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java?rev=824266&r1=824265&r2=824266&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java (original)
+++ sling/trunk/bundles/jcr/classloader/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java Mon Oct 12 08:53:33 2009
@@ -18,444 +18,69 @@
  */
 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.Dictionary;
-import java.util.Iterator;
-
-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.commons.collections.BidiMap;
-import org.apache.commons.collections.bidimap.DualHashBidiMap;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.commons.classloader.DynamicClassLoaderProvider;
-import org.apache.sling.commons.mime.MimeTypeService;
-import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.jcr.classloader.RepositoryClassLoaderProvider;
 import org.osgi.framework.Bundle;
 import org.osgi.service.component.ComponentContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * The <code>RepositoryClassLoaderProviderImpl</code> TODO
  *
- * @scr.component immediate="false" label="%loader.name"
- *      description="%loader.description"
+ * @scr.component inherit="false" label="%deprecatedloader.name"
+ *      description="%deprecatedloader.description"
  * @scr.property name="service.vendor" value="The Apache Software Foundation"
  * @scr.property name="service.description"
  *      value="Provides Repository ClassLoaders"
- * @scr.service servicefactory="true"
+ * @scr.service servicefactory="true" interface="RepositoryClassLoaderProvider"
+ * @scr.property nameRef="DynamicClassLoaderProviderImpl.CLASS_PATH_PROP" valueRefs0="DynamicClassLoaderProviderImpl.CLASS_PATH_DEFAULT"
+ * @scr.property nameRef="DynamicClassLoaderProviderImpl.OWNER_PROP" valueRef="DynamicClassLoaderProviderImpl.OWNER_DEFAULT"
+ * @scr.reference name="repository" interface="org.apache.sling.jcr.api.SlingRepository"
+ * @scr.reference name="mimeTypeService" policy="dynamic" interface="org.apache.sling.commons.mime.MimeTypeService"
  */
 public class RepositoryClassLoaderProviderImpl
-        implements RepositoryClassLoaderProvider, DynamicClassLoaderProvider, ClassLoaderWriter {
-
-    /** default log */
-    private static final Logger log = LoggerFactory.getLogger(RepositoryClassLoaderFacade.class);
-
-    /**
-     * @scr.property values0="/var/classes"
-     */
-    public static final String CLASS_PATH_PROP = "classpath";
-
-    /**
-     * @scr.property valueRef="OWNER_DEFAULT"
-     */
-    public static final String OWNER_PROP = "owner";
-
-    // JSP Class Loader class path will be injected to the class loader !
-    private static final String[] CLASS_PATH_DEFAULT = { };
-
-    private static final String OWNER_DEFAULT = "admin";
-
-    private BidiMap loaders = new DualHashBidiMap();
-
-    /**
-     * @scr.reference
-     */
-    private SlingRepository repository;
-
-    private String[] classPath;
-
-    private String classLoaderOwner;
+        extends DynamicClassLoaderProviderImpl
+        implements RepositoryClassLoaderProvider {
 
     private BundleProxyClassLoader parent;
 
-    /** @scr.reference policy="dynamic" */
-    private MimeTypeService mimeTypeService;
-
-    public ClassLoader getClassLoader(String owner) {
-        String classLoaderOwner = this.getClassLoaderOwner(owner);
-        RepositoryClassLoaderFacade loader =
-            (RepositoryClassLoaderFacade) this.loaders.get(classLoaderOwner);
-        if (loader == null) {
-            loader = new RepositoryClassLoaderFacade(this, this.parent,
-                classLoaderOwner, this.classPath);
-            this.loaders.put(classLoaderOwner, loader);
-        }
-
-        return loader;
-    }
-
-    public void ungetClassLoader(ClassLoader classLoader) {
-        // nothing to do
-    }
-
-    //---------- Support for RepositoryClassLoaderFacade ----------------------
-
-    /* package */ Session getSession(String owner) throws RepositoryException {
-        // get an administrative session for potentiall impersonation
-        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(owner)) {
-            return admin;
-        }
-
-        // else impersonate as the owner and logout the admin session again
-        try {
-            return admin.impersonate(new SimpleCredentials(owner, new char[0]));
-        } finally {
-            admin.logout();
-        }
-    }
+    private RepositoryClassLoaderFacade classLoaderFacade;
 
     /**
-     * @see org.apache.sling.commons.classloader.DynamicClassLoaderProvider#getClassLoader(ClassLoader)
+     * @see org.apache.sling.jcr.classloader.RepositoryClassLoaderProvider#getClassLoader(java.lang.String)
      */
-    public ClassLoader getClassLoader(final ClassLoader parent) {
-        // we just make up a unique identifier
-        final String classLoaderOwner = "DynamicClassLoaderProvider:" + parent.hashCode();
-        RepositoryClassLoaderFacade loader =
-            (RepositoryClassLoaderFacade) this.loaders.get(classLoaderOwner);
-        if (loader == null) {
-            loader = new RepositoryClassLoaderFacade(this, parent,
-                    this.classLoaderOwner, this.classPath);
-            this.loaders.put(classLoaderOwner, loader);
-        }
-
-        return loader;
-    }
-
-    //---------- SCR Integration ----------------------------------------------
-
-    /**
-     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#delete(java.lang.String)
-     */
-    public boolean delete(String name) {
-        name = cleanPath(name);
-        Node parentNode = null;
-        Session session = null;
-        try {
-            session = getSession(this.classLoaderOwner);
-            if (session.itemExists(name)) {
-                Item fileItem = session.getItem(name);
-                parentNode = fileItem.getParent();
-                fileItem.remove();
-                parentNode.save();
-                return true;
-            }
-        } catch (RepositoryException re) {
-            log.error("Cannot remove " + name, re);
-        } finally {
-            checkNode(parentNode, name);
-            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(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(String oldName, String newName) {
-        Session session = null;
-        try {
-            oldName = cleanPath(oldName);
-            newName = cleanPath(newName);
-
-            session = this.getSession(this.classLoaderOwner);
-            session.getWorkspace().move(oldName, newName);
-            return true;
-        } catch (RepositoryException re) {
-            log.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.
-     */
-    private boolean mkdirs(final Session session, String path) {
-        Node parentNode = null;
-        try {
-            // quick test
-            if (session.itemExists(path) && session.getItem(path).isNode()) {
-                return true;
-            }
-
-            // check path walking it down
-            Node current = session.getRootNode();
-            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 {
-                    if (parentNode == null) {
-                        parentNode = current;
-                    }
-                    current = current.addNode(names[i], "nt:folder");
-                }
-            }
-
-            if (parentNode != null) {
-                parentNode.save();
-                return true;
-            }
-
-        } catch (RepositoryException re) {
-            log.error("Cannot create folder path " + path, re);
-        } finally {
-            checkNode(parentNode, path);
-        }
-
-        // false in case of error or no need to create
-        return false;
-    }
-
-    private static void checkNode(Node node, String path) {
-        if (node != null && node.isModified()) {
-            try {
-                node.refresh(false);
-            } catch (RepositoryException re) {
-                log.error("Cannot refresh node for " + path
-                    + " after failed save", re);
-            }
-        }
-    }
-
-    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);
-        }
-
-        if ( this.classPath == null || this.classPath.length == 0 ) {
-            return path;
-        }
-        return this.classPath[0] + path;
-    }
-
-    private static class RepositoryOutputStream extends ByteArrayOutputStream {
-
-        private final RepositoryClassLoaderProviderImpl repositoryOutputProvider;
-
-        private final String fileName;
-
-        RepositoryOutputStream(RepositoryClassLoaderProviderImpl repositoryOutputProvider,
-                String fileName) {
-            this.repositoryOutputProvider = repositoryOutputProvider;
-            this.fileName = fileName;
-        }
-
-        public void close() throws IOException {
-            super.close();
-
-            Node parentNode = null;
-            Session session = null;
-            try {
-                session = repositoryOutputProvider.getSession(repositoryOutputProvider.classLoaderOwner);
-                final int lastPos = fileName.lastIndexOf('/');
-                if ( lastPos != -1 ) {
-                    repositoryOutputProvider.mkdirs(session, fileName.substring(0, lastPos));
-                }
-                Node fileNode = null;
-                Node contentNode = null;
-                if (session.itemExists(fileName)) {
-                    Item item = session.getItem(fileName);
-                    if (item.isNode()) {
-                        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();
-                        String name = item.getName();
-                        fileNode = parentNode.addNode(name, "nt:file");
-                        item.remove();
-                    }
-                } else {
-                    int lastSlash = fileName.lastIndexOf('/');
-                    if (lastSlash <= 0) {
-                        parentNode = session.getRootNode();
-                    } else {
-                        Item parent = session.getItem(fileName.substring(0,
-                            lastSlash));
-                        if (!parent.isNode()) {
-                            // TODO: fail
-                        }
-                        parentNode = (Node) parent;
-                    }
-                    String name = fileName.substring(lastSlash + 1);
-                    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);
-
-                parentNode.save();
-            } catch (RepositoryException re) {
-                log.error("Cannot write file " + fileName, re);
-                throw new IOException("Cannot write file " + fileName
-                    + ", reason: " + re.toString());
-            } finally {
-                checkNode(parentNode, fileName);
-                if ( session != null ) {
-                    session.logout();
-                }
-            }
+    public ClassLoader getClassLoader(String owner) {
+        if (this.classLoaderFacade == null) {
+            this.classLoaderFacade = new RepositoryClassLoaderFacade(this, this.parent,
+                this.getClassPaths());
         }
-    }
 
-    /**
-     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getInputStream(java.lang.String)
-     */
-    public InputStream getInputStream(String fileName)
-    throws IOException {
-        final String path = cleanPath(fileName) + "/jcr:content/jcr:data";
-        Session session = null;
-        try {
-            session = getSession(this.classLoaderOwner);
-            if ( session.itemExists(path) ) {
-                final Property prop = (Property)session.getItem(path);
-                return prop.getStream();
-            }
-            throw new FileNotFoundException("Unable to find " + fileName);
-        } catch (RepositoryException re) {
-            throw (IOException) new IOException(
-                        "Failed to get InputStream for " + fileName).initCause(re);
-        } finally {
-            if ( session != null ) {
-                session.logout();
-            }
-        }
+        return this.classLoaderFacade;
     }
 
     /**
-     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getLastModified(java.lang.String)
+     * @see org.apache.sling.jcr.classloader.RepositoryClassLoaderProvider#ungetClassLoader(java.lang.ClassLoader)
      */
-    public long getLastModified(String fileName) {
-        final String path = cleanPath(fileName) + "/jcr:content/jcr:lastModified";
-        Session session = null;
-        try {
-            session = getSession(this.classLoaderOwner);
-            if ( session.itemExists(path) ) {
-                final Property prop = (Property)session.getItem(path);
-                return prop.getLong();
-            }
-        } catch (RepositoryException se) {
-            log.error("Cannot get last modification time for " + fileName, se);
-        }
-
-        // fallback to "non-existant" in case of problems
-        return -1;
+    public void ungetClassLoader(ClassLoader classLoader) {
+        // nothing to do
     }
 
     protected void activate(ComponentContext componentContext) {
-        @SuppressWarnings("unchecked")
-        Dictionary properties = componentContext.getProperties();
-
-        Object prop = properties.get(CLASS_PATH_PROP);
-        this.classPath = (prop instanceof String[]) ? (String[]) prop : CLASS_PATH_DEFAULT;
-
-        prop = properties.get(OWNER_PROP);
-        this.classLoaderOwner = (prop instanceof String)? (String) prop : OWNER_DEFAULT;
-
-        Bundle owner = componentContext.getUsingBundle();
+        super.activate(componentContext);
+        final Bundle owner = componentContext.getUsingBundle();
 
         // if there is no using bundle, we have an error !!
         if (owner == null) {
             throw new IllegalStateException("Using Bundle expected. Is this a servicefactory component ?");
         }
-
         this.parent = new BundleProxyClassLoader(owner, null);
     }
 
     @SuppressWarnings("unchecked")
     protected void deactivate(ComponentContext componentContext) {
-        for (Iterator ci=this.loaders.values().iterator(); ci.hasNext(); ) {
-            RepositoryClassLoaderFacade cl = (RepositoryClassLoaderFacade) ci.next();
-            cl.destroy();
-            ci.remove();
+        if ( this.classLoaderFacade != null ) {
+            this.classLoaderFacade.destroy();
+            this.classLoaderFacade = null;
         }
-
         this.parent = null;
-    }
-
-    //---------- internal -----------------------------------------------------
-
-    private String getClassLoaderOwner(String userId) {
-        return this.classLoaderOwner;
+        super.deactivate(componentContext);
     }
 }

Modified: sling/trunk/bundles/jcr/classloader/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/classloader/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=824266&r1=824265&r2=824266&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/classloader/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ sling/trunk/bundles/jcr/classloader/src/main/resources/OSGI-INF/metatype/metatype.properties Mon Oct 12 08:53:33 2009
@@ -22,13 +22,17 @@
 # descriptions as used in the metatype.xml descriptor generated by the
 # the Sling SCR plugin
 
-loader.name = Apache Sling Repository Class Loader Factory
-loader.description = Configuration for the Repository Class Loader Factory. This \
+deprecatedloader.name = Apache Sling Repository Class Loader Factory
+deprecatedloader.description = Configuration for the Repository Class Loader Factory. This \
  configuration applies to all clients of the factory even though each Bundle \
  using the factory retrieves its own factory. The class path of the created \
  Repository Class Loaders is configurable and the class loaders delegate use \
  the bundle asking for the factory as the parent class loader.
 
+loader.name = Apache Sling Repository Class Loader Factory
+loader.description = Configuration for the Repository Class Loader. The class path of the created \
+ Repository Class Loaders is configurable.
+
 classpath.name = Class Path
 classpath.description = The class path in the repository to use as the class \
  path for all created Repository Class Loaders. All Class Loaders are configured \