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

[sling-org-apache-sling-jcr-classloader] 13/18: Experimental class loader writer for scripting engines.

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

rombert pushed a commit to annotated tag org.apache.sling.jcr.classloader-2.0.6
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-classloader.git

commit dea3efa0d3e719414e6af10c0f7ed5a0836c2f0b
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jul 17 06:16:52 2009 +0000

    Experimental class loader writer for scripting engines.
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/classloader@794977 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |   5 +
 .../internal/RepositoryClassLoaderFacade.java      |  31 +--
 .../RepositoryClassLoaderProviderImpl.java         | 308 ++++++++++++++++++++-
 3 files changed, 302 insertions(+), 42 deletions(-)

diff --git a/pom.xml b/pom.xml
index a36fceb..539ba29 100644
--- a/pom.xml
+++ b/pom.xml
@@ -99,6 +99,11 @@
             <version>0.9.0-SNAPSHOT</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.mime</artifactId>
+            <version>2.1.0-incubator</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.jackrabbit</groupId>
             <artifactId>jackrabbit-classloader</artifactId>
             <version>1.4.1</version>
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java b/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java
index cc5ff1a..9324105 100644
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java
+++ b/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderFacade.java
@@ -47,15 +47,6 @@ class RepositoryClassLoaderFacade extends URLClassLoader {
     private String[] classPath;
     private DynamicRepositoryClassLoader delegate;
 
-    /**
-     * The reference counter. If not greater than zero, there are this
-     * number of (assumed) life references.
-     *
-     * @see #ref()
-     * @see #deref()
-     */
-    private int refCtr = 0;
-
     public RepositoryClassLoaderFacade(
             RepositoryClassLoaderProviderImpl classLoaderProvider,
             ClassLoader parent,
@@ -140,27 +131,6 @@ class RepositoryClassLoaderFacade extends URLClassLoader {
         }
     }
 
-    /**
-     * Increases the reference counter of this class loader.
-     */
-    /* package */void ref() {
-        this.refCtr++;
-    }
-
-    /**
-     * Decreases the reference counter of this class loader and calls the
-     * base class <code>destroy()</code> method, if this class loader has
-     * already been destroyed by calling the {@link #destroy()} method.
-     */
-    /* package */void deref() {
-        this.refCtr--;
-
-        // destroy if the loader should be destroyed and no refs exist
-//        if (refCtr <= 0 /* && destroyed */ ) {
-//            destroy();
-//        }
-    }
-
     //---------- internal -----------------------------------------------------
 
     private Session getSession() throws RepositoryException {
@@ -197,4 +167,5 @@ class RepositoryClassLoaderFacade extends URLClassLoader {
 
         return this.delegate;
     }
+
 }
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java b/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java
index af5ee61..425c9b5 100644
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java
+++ b/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoaderProviderImpl.java
@@ -18,20 +18,33 @@
  */
 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
@@ -44,7 +57,10 @@ import org.osgi.service.component.ComponentContext;
  * @scr.service servicefactory="true"
  */
 public class RepositoryClassLoaderProviderImpl
-        implements RepositoryClassLoaderProvider, DynamicClassLoaderProvider {
+        implements RepositoryClassLoaderProvider, DynamicClassLoaderProvider, ClassLoaderWriter {
+
+    /** default log */
+    private static final Logger log = LoggerFactory.getLogger(RepositoryClassLoaderFacade.class);
 
     /**
      * @scr.property values0="/var/classes"
@@ -74,6 +90,9 @@ public class RepositoryClassLoaderProviderImpl
 
     private BundleProxyClassLoader parent;
 
+    /** @scr.reference policy="dynamic" */
+    private MimeTypeService mimeTypeService;
+
     public ClassLoader getClassLoader(String owner) {
         String classLoaderOwner = this.getClassLoaderOwner(owner);
         RepositoryClassLoaderFacade loader =
@@ -84,17 +103,11 @@ public class RepositoryClassLoaderProviderImpl
             this.loaders.put(classLoaderOwner, loader);
         }
 
-        // extend reference counter
-        loader.ref();
-
         return loader;
     }
 
     public void ungetClassLoader(ClassLoader classLoader) {
-        if (classLoader instanceof RepositoryClassLoaderFacade) {
-            RepositoryClassLoaderFacade cl = (RepositoryClassLoaderFacade) classLoader;
-            cl.deref();
-        }
+        // nothing to do
     }
 
     //---------- Support for RepositoryClassLoaderFacade ----------------------
@@ -126,18 +139,289 @@ public class RepositoryClassLoaderProviderImpl
             (RepositoryClassLoaderFacade) this.loaders.get(classLoaderOwner);
         if (loader == null) {
             loader = new RepositoryClassLoaderFacade(this, parent,
-                    OWNER_DEFAULT, this.classPath);
+                    this.classLoaderOwner, this.classPath);
             this.loaders.put(classLoaderOwner, loader);
         }
 
-        // extend reference counter
-        loader.ref();
-
         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();
+                }
+            }
+        }
+    }
+
+    /**
+     * @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();
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.sling.commons.classloader.ClassLoaderWriter#getLastModified(java.lang.String)
+     */
+    public long getLastModified(String fileName) {
+        final String path = cleanPath(fileName) + "/jcr:content/jcr:lastModifed";
+        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;
+    }
+
     protected void activate(ComponentContext componentContext) {
         @SuppressWarnings("unchecked")
         Dictionary properties = componentContext.getProperties();

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