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 <[email protected]> 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 "[email protected]" <[email protected]>.
