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 \