SLING-2447 : ClassLoaderWriter should provide class loader for loading written classes/resources
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1305516 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java b/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
index 10776f2..a86cd65 100644
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
+++ b/src/main/java/org/apache/sling/jcr/classloader/internal/ClassLoaderWriterImpl.java
@@ -136,7 +136,7 @@
/**
* Return a new session.
*/
- public Session getSession() throws RepositoryException {
+ public Session createSession() throws RepositoryException {
// get an administrative session for potentiall impersonation
final Session admin = this.repository.loginAdministrative(null);
@@ -180,7 +180,7 @@
final String path = cleanPath(name);
Session session = null;
try {
- session = getSession();
+ session = createSession();
if (session.itemExists(path)) {
Item fileItem = session.getItem(path);
fileItem.remove();
@@ -217,7 +217,7 @@
final String oldPath = cleanPath(oldName);
final String newPath = cleanPath(newName);
- session = this.getSession();
+ session = this.createSession();
session.move(oldPath, newPath);
session.save();
this.repositoryClassLoader.handleEvent(oldName);
@@ -338,7 +338,7 @@
Session session = null;
try {
// get an own session for writing
- session = repositoryOutputProvider.getSession();
+ session = repositoryOutputProvider.createSession();
final int lastPos = fileName.lastIndexOf('/');
final String path = (lastPos == -1 ? null : fileName.substring(0, lastPos));
final String name = (lastPos == -1 ? fileName : fileName.substring(lastPos + 1));
@@ -425,7 +425,7 @@
final String path = cleanPath(name) + "/jcr:content/jcr:data";
Session session = null;
try {
- session = this.getSession();
+ session = this.createSession();
if ( session.itemExists(path) ) {
final Property prop = (Property)session.getItem(path);
return prop.getStream();
@@ -448,7 +448,7 @@
final String path = cleanPath(name) + "/jcr:content/jcr:lastModified";
Session session = null;
try {
- session = this.getSession();
+ session = this.createSession();
if ( session.itemExists(path) ) {
final Property prop = (Property)session.getItem(path);
return prop.getLong();
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java b/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
index abf0690..d69aed5 100644
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
+++ b/src/main/java/org/apache/sling/jcr/classloader/internal/RepositoryClassLoader.java
@@ -34,7 +34,7 @@
import javax.jcr.Session;
import org.apache.sling.commons.classloader.DynamicClassLoader;
-import org.apache.sling.jcr.classloader.internal.net.URLFactory;
+import org.apache.sling.jcr.classloader.internal.net.JCRURLHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,11 +83,6 @@
private boolean destroyed = false;
/**
- * Session to serve urls.
- */
- private Session urlHandlerSession;
-
- /**
* Creates a <code>RepositoryClassLoader</code> for a given
* repository path.
*
@@ -140,11 +135,6 @@
// set destroyal guard
destroyed = true;
- if ( this.urlHandlerSession != null ) {
- this.urlHandlerSession.logout();
- this.urlHandlerSession = null;
- }
-
this.writer = null;
this.repositoryPath = null;
synchronized ( this.usedResources ) {
@@ -202,7 +192,7 @@
try {
if ( findClassLoaderResource(path) != null ) {
logger.debug("findResource: Getting resource from {}", path);
- return URLFactory.createURL(this.getUrlHandlerSession(), path);
+ return JCRURLHandler.createURL(this.writer, path);
}
} catch (final Exception e) {
logger.warn("findResource: Cannot getURL for " + name, e);
@@ -211,21 +201,6 @@
return null;
}
- private synchronized Session getUrlHandlerSession() {
- if ( this.urlHandlerSession != null && !this.urlHandlerSession.isLive() ) {
- this.urlHandlerSession.logout();
- this.urlHandlerSession = null;
- }
- if ( this.urlHandlerSession == null ) {
- try {
- this.urlHandlerSession = this.writer.getSession();
- } catch ( final RepositoryException re ) {
- logger.warn("Unable to create new session.", re);
- }
- }
- return this.urlHandlerSession;
- }
-
/**
* Returns an Enumeration of URLs representing all of the resources
* on the search path having the specified name.
@@ -324,7 +299,7 @@
Session session = null;
byte[] res = null;
try {
- session = this.writer.getSession();
+ session = this.writer.createSession();
if ( session.itemExists(path) ) {
final Node node = (Node)session.getItem(path);
logger.debug("Found resource at {}", path);
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/net/FileParts.java b/src/main/java/org/apache/sling/jcr/classloader/internal/net/FileParts.java
deleted file mode 100644
index 3e6eaa4..0000000
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/net/FileParts.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * 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.net;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-
-import javax.jcr.Session;
-
-/**
- * The <code>FileParts</code> class provides composing and parsing functionality
- * to create and analize JCR Repository URL file components.
- * <p>
- * The file component of a JCR Repository URL has the format
- * <pre>
- * file = [ "jcr:" [ "//" authority ] ] "/" repository "/" workspace jarpath .
- * authority = // URL authority specification
- * repository = // URL encoded repository name
- * workspace = // URL encoded workspace name
- * jarpath = path [ "!/" [ entry ] ] .
- * path = // The absolute item path (with a leading slash)
- * entry = // The (relative) path to the entry in an archive
- * </pre>
- * <p>
- * To facitility use of this class with JCRJar URLs, the
- * {@link #FileParts(String)} supports file specifications which contains
- * the JCR Repository URL scheme name and an optional URL authority
- * specification. This prefix in front of the real file specification is
- * silently discarded. It is not included in the string representation returned
- * by the {@link #toString()} method.
- * <p>
- * To make sure parsing is not complicated by implementation and use case
- * specific repository and workspace names, those names are URL encoded using
- * the <code>URLEncoder</code> class and <i>UTF-8</i> character encoding.
- *
- * @author Felix Meschberger
- */
-class FileParts {
-
- /** The decoded name of the repository */
- private final String repository;
-
- /** The decoded name of the workspace */
- private final String workspace;
-
- /** The repository item path part of the URL path */
- private final String path;
-
- /**
- * The path to the entry in the archive, if the file spec contains the
- * jar entry separator <i>!/</i>. If no entry path is specified, this is
- * <code>null</code>. If no path is specified after the <i>!/</i> this
- * is an empty string.
- */
- private final String entryPath;
-
- /**
- * Creates a new instance for the root node of the given session. The
- * repository name is currently set to the fixed string "_" as there has not
- * been established a repository naming convention yet. The name of the
- * workspace is set to the name of the workspace to which the session is
- * attached. The path is set to <code>"/"</code> to indicate the root node
- * if the <code>path</code> argument is <code>null</code>.
- *
- * @param session The session for which to create this instance.
- * @param path The absolute item path to initialize this instance with. If
- * <code>null</code> the item path is set to the <code>/</code>.
- * @param entryPath The path to the archive entry to set on this instance.
- * This is expected to be a relative path without a leading slash and
- * may be <code>null</code>.
- *
- * @throws NullPointerException if <code>session</code> is
- * <code>null</code>.
- */
- FileParts(Session session, String path, String entryPath) {
- this.repository = "_";
- this.workspace = session.getWorkspace().getName();
- this.path = (path == null) ? "/" : path;
- this.entryPath = entryPath;
- }
-
- /**
- * Creates an instance of this class setting the repository, workspace and
- * path fields from the given <code>file</code> specification.
- *
- * @param file The specification providing the repository, workspace and
- * path values.
- *
- * @throws NullPointerException if <code>file</code> is
- * <code>null</code>.
- * @throws IllegalArgumentException if <code>file</code> is not the
- * correct format.
- */
- FileParts(String file) {
- if (!file.startsWith("/")) {
- if (file.startsWith(URLFactory.REPOSITORY_SCHEME+":")) {
- file = strip(file);
- } else {
- throw failure("Not an absolute file", file);
- }
- }
-
- // find the repository name
- int slash0 = 1;
- int slash1 = file.indexOf('/', slash0);
- if (slash1 < 0 || slash1-slash0 == 0) {
- throw failure("Missing repository name", file);
- }
- this.repository = decode(file.substring(slash0, slash1));
-
- // find the workspace name
- slash0 = slash1 + 1;
- slash1 = file.indexOf('/', slash0);
- if (slash1 < 0 || slash1-slash0 == 0) {
- throw failure("Missing workspace name", file);
- }
- this.workspace = decode(file.substring(slash0, slash1));
-
- String fullPath = file.substring(slash1);
- int bangSlash = indexOfBangSlash(fullPath);
- if (bangSlash < 0) {
- this.path = fullPath;
- this.entryPath = null;
- } else {
- this.path = fullPath.substring(0, bangSlash-1);
- this.entryPath = fullPath.substring(bangSlash+1);
- }
- }
-
- /**
- * Finds the position of the bang slash (!/) in the file part of the URL.
- */
- static int indexOfBangSlash(String file) {
-
- for (int i = file.length(); (i = file.lastIndexOf('!', i)) != -1; i--) {
- if (i != file.length() - 1 && file.charAt(i + 1) == '/') {
- return i + 1;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the plain name of the repository.
- */
- String getRepository() {
- return repository;
- }
-
- /**
- * Returns the plain name of the workspace.
- */
- String getWorkspace() {
- return workspace;
- }
-
- /**
- * Returns the absolute repository path of the item.
- */
- String getPath() {
- return path;
- }
-
- /**
- * Returns the entry path of <code>null</code> if no entry exists.
- */
- String getEntryPath() {
- return entryPath;
- }
-
- //---------- Object overwrites --------------------------------------------
-
- /**
- * Returns a hash code for this instance composed of the hash codes of the
- * repository, workspace and path names.
- */
- public int hashCode() {
- return getRepository().hashCode() +
- 17 * getWorkspace().hashCode() +
- 33 * getPath().hashCode();
- }
-
- /**
- * Returns <code>true</code> if <code>obj</code> is the same as this or
- * if other is a <code>FileParts</code> with the same path, workspace and
- * repository. Otherwise <code>false</code> is returned.
- */
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- } else if (obj instanceof FileParts) {
- FileParts other = (FileParts) obj;
-
- // catch null entry path, fail if other has a defined entry path
- if (getEntryPath() == null) {
- if (other.getEntryPath() != null) {
- return false;
- }
- }
-
- return getPath().equals(other.getPath()) &&
- getWorkspace().equals(other.getWorkspace()) &&
- getRepository().equals(other.getRepository()) &&
- getEntryPath().equals(other.getEntryPath());
- }
-
- // fall back on null or other class
- return false;
- }
-
- /**
- * Returns the encoded string representation of this instance, which may
- * later be fed to the {@link #FileParts(String)} constructor to recreate
- * an equivalent instance.
- */
- public String toString() {
- StringBuilder buf = new StringBuilder();
- buf.append('/').append(encode(getRepository()));
- buf.append('/').append(encode(getWorkspace()));
- buf.append(getPath());
-
- if (getEntryPath() != null) {
- buf.append("!/").append(getEntryPath());
- }
-
- return buf.toString();
- }
-
- //---------- internal -----------------------------------------------------
-
- /**
- * @throws IllegalArgumentException If there is no path element after the
- * authority.
- */
- private String strip(String file) {
- // cut off jcr: prefix - any other prefix, incl. double slash
- // would cause an exception to be thrown in the constructor
- int start = 4;
-
- // check whether the remainder contains an authority specification
- if (file.length() >= start+2 && file.charAt(start) == '/' &&
- file.charAt(start+1) == '/') {
-
- // find the slash after the authority, fail if missing
- start = file.indexOf('/', start + 2);
- if (start < 0) {
- throw failure("Missing path after authority", file);
- }
- }
-
- // return the file now
- return file.substring(start);
- }
-
- /**
- * Encodes the given string value using the <code>URLEncoder</code> and
- * <i>UTF-8</i> character encoding.
- *
- * @param value The string value to encode.
- *
- * @return The encoded string value.
- *
- * @throws InternalError If <code>UTF-8</code> character set encoding is
- * not supported. As <code>UTF-8</code> is required to be implemented
- * on any Java platform, this error is not expected.
- */
- private String encode(String value) {
- try {
- return URLEncoder.encode(value, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- // not expected, throw an InternalError
- throw new InternalError("UTF-8 not supported");
- }
- }
-
- /**
- * Decodes the given string value using the <code>URLDecoder</code> and
- * <i>UTF-8</i> character encoding.
- *
- * @param value The string value to decode.
- *
- * @return The decoded string value.
- *
- * @throws InternalError If <code>UTF-8</code> character set encoding is
- * not supported. As <code>UTF-8</code> is required to be implemented
- * on any Java platform, this error is not expected.
- */
- private String decode(String value) {
- try {
- return URLDecoder.decode(value, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- // not expected, throw an InternalError
- throw new InternalError("UTF-8 not supported");
- }
- }
-
- /**
- * Returns a <code>IllegalArgumentException</code> formatted with the
- * given reason and causing file specification.
- *
- * @param reason The failure reason.
- * @param file The original file specification leading to failure.
- *
- * @return A <code>IllegalArgumentException</code> with the given
- * reason and causing file specification.
- */
- private IllegalArgumentException failure(String reason, String file) {
- return new IllegalArgumentException(reason + ": '" + file + "'");
- }
-}
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLConnection.java b/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLConnection.java
index 1cf7509..15c92ac 100644
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLConnection.java
+++ b/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLConnection.java
@@ -16,6 +16,7 @@
*/
package org.apache.sling.jcr.classloader.internal.net;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -26,7 +27,6 @@
import java.util.List;
import java.util.Map;
-import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
@@ -63,17 +63,6 @@
* {@link #connect()} fails and access to the content is not possible.
* </ul>
* <p>
- * After having connected the property is available through the
- * {@link #getProperty()} method. Other methods exist to retrieve repository
- * related information defined when creating the URL: {@link #getSession()} to
- * retrieve the session of the URL, {@link #getPath()} to retrieve the path
- * with which the URL was created and {@link #getItem()} to retrieve the item
- * with which the URL was created. The results of calling {@link #getProperty()}
- * and {@link #getItem()} will be the same if the URL directly addressed the
- * property. If the URL addressed the node whose primary item chain ultimately
- * resolved to the property, the {@link #getItem()} will return the node and
- * {@link #getProperty()} will return the resolved property.
- * <p>
* A note on the <code>InputStream</code> available from
* {@link #getInputStream()}: Unlike other implementations - for example
* for <code>file:</code> or <code>http:</code> URLs - which return the same
@@ -119,39 +108,39 @@
* The name of the header containing the content size (value is
* "content-length").
*/
- protected static final String CONTENT_LENGTH = "content-length";
+ private static final String CONTENT_LENGTH = "content-length";
/**
* The name of the header containing the MIME type of the content (value is
* "content-type").
*/
- protected static final String CONTENT_TYPE = "content-type";
+ private static final String CONTENT_TYPE = "content-type";
/**
* The name of the header containing the content encoding (value is
* "content-encoding").
*/
- protected static final String CONTENT_ENCODING = "content-encoding";
+ private static final String CONTENT_ENCODING = "content-encoding";
/**
* The name of the header containing the last modification time stamp of
* the content (value is "last-modified").
*/
- protected static final String LAST_MODIFIED = "last-modified";
+ private static final String LAST_MODIFIED = "last-modified";
/**
* The default content type name for binary properties accessed by this
* connection (value is "application/octet-stream").
* @see #connect()
*/
- protected static final String APPLICATION_OCTET = "application/octet-stream";
+ private static final String APPLICATION_OCTET = "application/octet-stream";
/**
* The default content type name for non-binary properties accessed by this
* connection (value is "text/plain").
* @see #connect()
*/
- protected static final String TEXT_PLAIN = "text/plain";
+ private static final String TEXT_PLAIN = "text/plain";
/**
* The handler associated with the URL of this connection. This handler
@@ -161,31 +150,13 @@
private final JCRURLHandler handler;
/**
- * The {@link FileParts} encapsulating the repository name, workspace name,
- * item path and optional archive entry path contained in the file part
- * of the URL. This field is set on-demand by the {@link #getFileParts()}
- * method.
- *
- * @see #getFileParts()
- */
- private FileParts fileParts;
-
- /**
- * The <code>Item</code> addressed by the path of this connection's URL.
- * This field is set on-demand by the {@link #getItem()} method.
- *
- * @see #getItem()
- */
- private Item item;
-
- /**
* The <code>Property</code> associated with the URLConnection. The field
* is only set after the connection has been successfully opened.
*
* @see #getProperty()
* @see #connect()
*/
- private Property property;
+ private byte[] contents;
/**
* The (guessed) content type of the data. Currently the content type is
@@ -244,52 +215,19 @@
* @param url The URL to base the connection on.
* @param handler The URL handler supporting the given URL.
*/
- JCRURLConnection(URL url, JCRURLHandler handler) {
+ JCRURLConnection(final URL url, final JCRURLHandler handler) {
super(url);
this.handler = handler;
}
/**
- * Returns the current session of URL.
- * <p>
- * Calling this method does not require this connection being connected.
- */
- public Session getSession() {
- return handler.getSession();
- }
-
- /**
* Returns the path to the repository item underlying the URL of this
* connection.
* <p>
* Calling this method does not require this connection being connected.
*/
- public String getPath() {
- return getFileParts().getPath();
- }
-
- /**
- * Returns the repository item underlying the URL of this connection
- * retrieved through the path set on the URL.
- * <p>
- * Calling this method does not require this connection being connected.
- *
- * @throws IOException If the item has to be retrieved from the repository
- * <code>Session</code> of this connection and an error occurrs. The
- * cause of the exception will refer to the exception thrown from the
- * repository. If the path addresses a non-existing item, the cause
- * will be a <code>PathNotFoundException</code>.
- */
- public Item getItem() throws IOException {
- if (item == null) {
- try {
- item = getSession().getItem(getPath());
- } catch (RepositoryException re) {
- throw failure("getItem", re.toString(), re);
- }
- }
-
- return item;
+ private String getPath() {
+ return this.handler.getPath();
}
/**
@@ -304,18 +242,17 @@
*
* @see #connect()
*/
- public Property getProperty() throws IOException {
+ private byte[] getContents() throws IOException {
// connect to set the property value
connect();
- return property;
+ return this.contents;
}
//---------- URLConnection overwrites -------------------------------------
/**
- * Connects to the URL setting the header fields and preparing for the
- * {@link #getProperty()} and {@link #getInputStream()} methods.
+ * Connects to the URL setting the header fields and getting the contents.
* <p>
* The following algorithm is applied:
* <ol>
@@ -353,22 +290,25 @@
* exception.
*/
public synchronized void connect() throws IOException {
- // todo: The ContentBus URL must also contain version information on
if (!connected) {
// Get hold of the data
+ Session session = null;
try {
+ session = this.handler.getClassLoaderWriter().createSession();
+ final Node node = (Node)session.getItem(this.getPath());
// resolve the URLs item to a property
- Property property = Util.getProperty(getItem());
+ final Property property = Util.getProperty(node);
if (property == null) {
throw failure("connect",
"Multivalue property not supported", null);
}
+ final byte[] contents = Util.getBytes(node);
+
// values to set later
String contentType;
String contentEncoding = null; // no defined content encoding
- int contentLength = (int) property.getLength();
long lastModified;
Node parent = property.getParent();
@@ -381,7 +321,7 @@
if (parent.hasProperty("jcr:mimeType")) {
contentType = parent.getProperty("jcr:mimeType").getString();
} else {
- contentType = guessContentTypeFromName(getItem().getName());
+ contentType = guessContentTypeFromName(node.getName());
if (contentType == null) {
contentType = (property.getType() == PropertyType.BINARY)
? APPLICATION_OCTET
@@ -399,17 +339,21 @@
new Integer(contentLength) });
// set the fields
- setProperty(property);
- setContentType(contentType);
- setContentEncoding(contentEncoding);
- setContentLength(contentLength);
- setLastModified(lastModified);
+ this.contents = contents;
+ this.contentType = contentType;
+ this.contentEncoding = contentEncoding;
+ this.contentLength = contents.length;
+ this.lastModified = lastModified;
// mark connection open
connected = true;
- } catch (RepositoryException re) {
+ } catch (final RepositoryException re) {
throw failure("connect", re.toString(), re);
+ } finally {
+ if ( session != null ) {
+ session.logout();
+ }
}
}
}
@@ -434,11 +378,7 @@
* @see #connect()
*/
public InputStream getInputStream() throws IOException {
- try {
- return getProperty().getStream();
- } catch (RepositoryException re) {
- throw failure("getInputStream", re.toString(), re);
- }
+ return new ByteArrayInputStream(this.getContents());
}
/**
@@ -680,62 +620,6 @@
return -1;
}
- //---------- implementation helpers ----------------------------------------
-
- /**
- * Returns the URL handler of the URL of this connection.
- */
- protected JCRURLHandler getHandler() {
- return handler;
- }
-
- /**
- * Returns the {@link FileParts} object which contains the decomposed file
- * part of this connection's URL.
- */
- FileParts getFileParts() {
- if (fileParts == null) {
- fileParts = new FileParts(getURL().getFile());
- }
-
- return fileParts;
- }
-
- /**
- * @param contentEncoding The contentEncoding to set.
- */
- protected void setContentEncoding(String contentEncoding) {
- this.contentEncoding = contentEncoding;
- }
-
- /**
- * @param contentLength The contentLength to set.
- */
- protected void setContentLength(int contentLength) {
- this.contentLength = contentLength;
- }
-
- /**
- * @param contentType The contentType to set.
- */
- protected void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- /**
- * @param lastModified The lastModified to set.
- */
- protected void setLastModified(long lastModified) {
- this.lastModified = lastModified;
- }
-
- /**
- * @param property The property to set.
- */
- protected void setProperty(Property property) {
- this.property = property;
- }
-
//---------- internal -----------------------------------------------------
/**
@@ -751,7 +635,7 @@
*
* @return The IOException the caller may throw.
*/
- protected IOException failure(String method, String message, Throwable cause) {
+ private IOException failure(String method, String message, Throwable cause) {
log.info(method + ": URL: " + url.toExternalForm() + ", Reason: "
+ message);
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLHandler.java b/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLHandler.java
index 1fa72c6..5360096 100644
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLHandler.java
+++ b/src/main/java/org/apache/sling/jcr/classloader/internal/net/JCRURLHandler.java
@@ -16,11 +16,12 @@
*/
package org.apache.sling.jcr.classloader.internal.net;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
-import javax.jcr.Session;
+import org.apache.sling.jcr.classloader.internal.ClassLoaderWriterImpl;
/**
* The <code>JCRURLHandler</code> is the <code>URLStreamHandler</code> for
@@ -29,49 +30,77 @@
* JCR Repository URLs have not been standardized yet and may only be created
* in the context of an existing <code>Session</code>. Therefore this handler
* is not globally available and JCR Repository URLs may only be created through
- * the factory methods in the {@link org.apache.sling.jcr.classloader.internal.net.URLFactory}
- * class.
+ * the factory method.
* <p>
* This class is not intended to be subclassed or instantiated by clients.
*
- * @author Felix Meschberger
- *
* @see org.apache.sling.jcr.classloader.internal.net.JCRURLConnection
- * @see org.apache.sling.jcr.classloader.internal.net.URLFactory
- * @see org.apache.sling.jcr.classloader.internal.net.URLFactory#createURL(Session, String)
*/
-class JCRURLHandler extends URLStreamHandler {
+public class JCRURLHandler extends URLStreamHandler {
/**
- * The session used to create this handler, which is also used to open
- * the connection object.
- *
- * @see #getSession()
+ * The scheme for JCR Repository URLs (value is "jcr").
*/
- private final Session session;
+ private static final String REPOSITORY_SCHEME = "jcr";
+
+ /**
+ * The writer provides access to a new session.
+ *
+ * @see #createSession()
+ */
+ private final ClassLoaderWriterImpl writer;
+
+ /**
+ * The repository path to the underlying item.
+ */
+ private final String path;
+
+ /**
+ * Creates a new JCR Repository URL for the given session and item path.
+ *
+ * @param writer The writer session providing access to the item.
+ * @param path The absolute path to the item. This must be an absolute
+ * path with a leading slash character. If this is <code>null</code>
+ * the root node path - <code>/</code> - is assumed.
+ *
+ * @return The JCR Repository URL
+ *
+ * @throws MalformedURLException If an error occurrs creating the
+ * <code>URL</code> instance.
+ */
+ public static URL createURL(final ClassLoaderWriterImpl writer, final String path)
+ throws MalformedURLException {
+ return new URL(REPOSITORY_SCHEME, "", -1,
+ path,
+ new JCRURLHandler(writer, path));
+ }
/**
* Creates a new instance of the <code>JCRURLHandler</code> with the
* given session.
*
- * @param session The <code>Session</code> supporting this handler. This
- * must not be <code>null</code>.
+ * @param writer The dynamic class loader writer
*
* @throws NullPointerException if <code>session</code> is <code>null</code>.
*/
- JCRURLHandler(Session session) {
- if (session == null) {
- throw new NullPointerException("session");
+ JCRURLHandler(final ClassLoaderWriterImpl writer, final String path) {
+ if (writer == null) {
+ throw new NullPointerException("writer");
}
- this.session = session;
+ this.writer = writer;
+ this.path = path;
}
/**
* Returns the session supporting this handler.
*/
- Session getSession() {
- return session;
+ ClassLoaderWriterImpl getClassLoaderWriter() {
+ return this.writer;
+ }
+
+ String getPath() {
+ return this.path;
}
//---------- URLStreamHandler abstracts ------------------------------------
@@ -85,63 +114,7 @@
*
* @see JCRURLConnection
*/
- protected URLConnection openConnection(URL url) {
+ protected URLConnection openConnection(final URL url) {
return new JCRURLConnection(url, this);
}
-
- /**
- * Checks the new <code>authority</code> and <code>path</code> before
- * actually setting the values on the url calling the base class
- * implementation.
- * <p>
- * We check the authority to not have been modified from the original URL,
- * as the authority is dependent on the repository <code>Session</code> on
- * which this handler is based and which was used to create the original
- * URL. Likewise the repository and workspace name parts of the path must
- * not have changed.
- *
- * @param u the URL to modify.
- * @param protocol the protocol name.
- * @param host the remote host value for the URL.
- * @param port the port on the remote machine.
- * @param authority the authority part for the URL.
- * @param userInfo the userInfo part of the URL.
- * @param path the path component of the URL.
- * @param query the query part for the URL.
- * @param ref the reference.
- *
- * @throws IllegalArgumentException if the authority or the repository name
- * or workspace name parts of the path has changed.
- */
- protected void setURL(URL u, String protocol, String host, int port,
- String authority, String userInfo, String path, String query, String ref) {
-
- // check for authority
- if (u.getAuthority() != authority) {
- if (u.getAuthority() == null) {
- if (authority != null) {
- throw new IllegalArgumentException("Authority " +
- authority + " not supported by this handler");
- }
- } else if (!u.getAuthority().equals(authority)) {
- throw new IllegalArgumentException("Authority " +
- authority + " not supported by this handler");
- }
- }
-
- // check for repository and/or workspace modifications
- FileParts newParts = new FileParts(path);
- if (!"_".equals(newParts.getRepository())) {
- throw new IllegalArgumentException("Repository " +
- newParts.getRepository() + " not supported by this handler");
- }
- if (!session.getWorkspace().getName().equals(newParts.getWorkspace())) {
- throw new IllegalArgumentException("Workspace " +
- newParts.getWorkspace() + " not supported by this handler");
- }
-
- // finally set the new values on the URL
- super.setURL(u, protocol, host, port, authority, userInfo, path, query,
- ref);
- }
}
diff --git a/src/main/java/org/apache/sling/jcr/classloader/internal/net/URLFactory.java b/src/main/java/org/apache/sling/jcr/classloader/internal/net/URLFactory.java
deleted file mode 100644
index 1d64dac..0000000
--- a/src/main/java/org/apache/sling/jcr/classloader/internal/net/URLFactory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.net;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.jcr.Session;
-
-/**
- * The <code>URLFactory</code> class provides factory methods for creating
- * JCR Repository and JCRJar URLs.
- * <p>
- * This class is not intended to be subclassed or instantiated by clients.
- *
- * @author Felix Meschberger
- */
-public final class URLFactory {
-
- /**
- * The scheme for JCR Repository URLs (value is "jcr").
- */
- public static final String REPOSITORY_SCHEME = "jcr";
-
- /**
- * The scheme for JCRJar URLs (value is "jar").
- */
- public static final String REPOSITORY_JAR_SCHEME = "jar";
-
- /** Private default constructor, not to be instantiated */
- private URLFactory() {
- }
-
- /**
- * Creates a new JCR Repository URL for the given session and item path.
- *
- * @param session The repository session providing access to the item.
- * @param path The absolute path to the item. This must be an absolute
- * path with a leading slash character. If this is <code>null</code>
- * the root node path - <code>/</code> - is assumed.
- *
- * @return The JCR Repository URL
- *
- * @throws MalformedURLException If an error occurrs creating the
- * <code>URL</code> instance.
- */
- public static URL createURL(Session session, String path)
- throws MalformedURLException {
-
- return new URL(REPOSITORY_SCHEME, "", -1,
- new FileParts(session, path, null).toString(),
- new JCRURLHandler(session));
- }
-}