You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by fm...@apache.org on 2005/12/21 15:14:24 UTC
svn commit: r358296 [4/5] - in
/incubator/jackrabbit/trunk/contrib/classloader: ./ src/ src/main/
src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/jackrabbit/
src/main/java/org/apache/jackrabbit/classloader/ src/main...
Added: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLConnection.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLConnection.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLConnection.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLConnection.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.classloader.Util;
+
+
+/**
+ * The <code>JCRURLConnection</code> is the <code>URLConnection</code>
+ * implementation to access the data addressed by a JCR Repository URL.
+ * <p>
+ * As the primary use of a <code>URLConnection</code> and thus the
+ * <code>JCRURLConnection</code> is to provide access to the content of a
+ * resource identified by the URL, it is the primary task of this class to
+ * identify and access a repository <code>Property</code> based on the URL. This
+ * main task is executed in the {@link #connect()} method.
+ * <p>
+ * Basically the guideposts to access content from a JCR Repository URl are
+ * the following:
+ * <ul>
+ * <li>The URL must ultimately resolve to a repository property to provide
+ * content.
+ * <li>If the URL itself is the path to a property, that property is used to
+ * provide the content.
+ * <li>If the URL is a path to a node, the primary item chain starting with
+ * this node is followed until no further primary items exist. If the
+ * final item is a property, that property is used to provide the content.
+ * <li>If neither of the above methods resolve to a property, the
+ * {@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
+ * stream on each call, this implementation returns a new stream on each
+ * invocation.
+ * <p>
+ * The following header fields are implemented by this class:
+ * <dl>
+ * <dt><code>Content-Length</code>
+ * <dd>The size of the content is filled from the <code>Property.getLength()</code>
+ * method, which returns the size in bytes of the property's value for
+ * binary values and the number of characters used for the string
+ * representation of the value for all other value types.
+ *
+ * <dt><code>Content-Type</code>
+ * <dd>If the property is a child of a <code>nt:resource</code> node, the
+ * content type is retrieved from the <code>jcr:mimeType</code>
+ * property of the parent node. If the parent node is not a
+ * <code>nt:resource</code>, the <code>guessContentTypeFromName</code>
+ * method is called on the {@link #getPath() path}. If this does not
+ * yield a content type, it is set to <code>application/octet-stream</code>
+ * for binary properties and to <code>text/plain</code> for other types.
+ *
+ * <dt><code>Content-Enconding</code>
+ * <dd>If the property is a child of a <code>nt:resource</code> node, the
+ * content encoding is retrieved from the <code>jcr:econding</code>
+ * property of the parent node. If the <code>jcr:encoding</code> property
+ * is not set, this header field remains undefined (aka <code>null</code>).
+ *
+ * <dt><code>Last-Modified</code>
+ * <dd>If the property is a child of a <code>nt:resource</code> node, the
+ * last modified type is retrieved from the <code>jcr:lastModified</code>
+ * property of the parent node. If the parent node is not a
+ * <code>nt:resource</code>, the last modification time is set to zero.
+ * </dl>
+ * <p>
+ * This class is not intended to be subclassed or instantiated by clients.
+ *
+ * @author Felix Meschberger
+ * @version $Rev:$, $Date:$
+ */
+public class JCRURLConnection extends URLConnection {
+
+ /** Default logging */
+ private static final Log log = LogFactory.getLog(JCRURLConnection.class);
+
+ /**
+ * The name of the header containing the content size (value is
+ * "content-length").
+ */
+ protected 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";
+
+ /**
+ * The name of the header containing the content encoding (value is
+ * "content-encoding").
+ */
+ protected 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";
+
+ /**
+ * 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";
+
+ /**
+ * 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";
+
+ /**
+ * The handler associated with the URL of this connection. This handler
+ * provides the connection with access to the repository and the item
+ * underlying the URL.
+ */
+ 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;
+
+ /**
+ * The (guessed) content type of the data. Currently the content type is
+ * guessed based on the path name of the page or the binary attribute of the
+ * atom.
+ * <p>
+ * Implementations are free to decide, how to define the content type. But
+ * they are required to set the type in the {@link #connect(Ticket)}method.
+ *
+ * @see #getContentType()
+ * @see #connect()
+ */
+ private String contentType;
+
+ /**
+ * The (guessed) content encoding of the data. Currently the content type is
+ * guessed based on the path name of the page or the binary attribute of the
+ * atom.
+ * <p>
+ * Implementations are free to decide, how to define the content type. But
+ * they are required to set the type in the {@link #connect(Ticket)}method.
+ *
+ * @see #getContentEncoding()
+ * @see #connect()
+ */
+ private String contentEncoding;
+
+ /**
+ * The content lentgh of the data, which is the size field of the atom
+ * status information of the base atom.
+ * <p>
+ * Implementations are free to decide, how to define the content length. But
+ * they are required to set the type in the {@link #connect(Ticket)}method.
+ *
+ * @see #getContentLength()
+ * @see #connect()
+ */
+ private int contentLength;
+
+ /**
+ * The last modification time in milliseconds since the epoch (1970/01/01)
+ * <p>
+ * Implementations are free to decide, how to define the last modification
+ * time. But they are required to set the type in the
+ * {@link #connect(Ticket)}method.
+ *
+ * @see #getLastModified()
+ * @see #connect()
+ */
+ private long lastModified;
+
+ /**
+ * Creates an instance of this class for the given <code>url</code>
+ * supported by the <code>handler</code>.
+ *
+ * @param url The URL to base the connection on.
+ * @param handler The URL handler supporting the given URL.
+ */
+ JCRURLConnection(URL url, 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;
+ }
+
+ /**
+ * Returns the repository <code>Property</code> providing the contents of
+ * this connection.
+ * <p>
+ * Calling this method forces the connection to be opened by calling the
+ * {@link #connect()} method.
+ *
+ * @throws IOException May be thrown by the {@link #connect()} method called
+ * by this method.
+ *
+ * @see #connect()
+ */
+ public Property getProperty() throws IOException {
+ // connect to set the property value
+ connect();
+
+ return property;
+ }
+
+ //---------- URLConnection overwrites -------------------------------------
+
+ /**
+ * Connects to the URL setting the header fields and preparing for the
+ * {@link #getProperty()} and {@link #getInputStream()} methods.
+ * <p>
+ * The following algorithm is applied:
+ * <ol>
+ * <li>The repository item is retrieved from the URL's
+ * <code>URLHandler</code>.
+ * <li>If the item is a node, the <code>getPrimaryItem</code> method is
+ * called on that node. If the node has no primary item, the connection
+ * fails.
+ * <li>If the item - either from the handler or after calling
+ * <code>getPrimaryItem</code> is still a node, this method fails
+ * because a <code>Property</code> is required for a successfull
+ * connection.
+ * <li>If the property found above is a multi-valued property, connection
+ * fails, because multi-valued properties are not currently supported.
+ * <li>The content length header field is set from the property length
+ * (<code>Property.getLength())</code>).
+ * <li>If the property's parent node is of node type <code>nt:resource</code>,
+ * the header fields for the content type, content encoding and last
+ * modification time are set from the <code>jcr:mimeType</code>,
+ * <code>jcr:encoding</code>, and <code>jcr:lastModification</code>
+ * properties. Otherwise the content encoding field is set to
+ * <code>null</code> and the last modification time is set to zero.
+ * The content type field is guessed from the name of the URL item.
+ * If the content type cannot be guessed, it is set to
+ * <code>application/octet-stream</code> if the property is of binary
+ * type or <code>text/plain</code> otherwise.
+ * </ol>
+ * <p>
+ * When this method successfully returns, this connection is considered
+ * connected. In case of an exception thrown, the connection is not
+ * connected.
+ *
+ * @throws IOException if an error occurrs retrieving the data property or
+ * any of the header field value properties or if any other errors
+ * occurrs. Any cuasing exception is set as the cause of this
+ * exception.
+ */
+ public synchronized void connect() throws IOException {
+ // todo: The ContentBus URL must also contain version information on
+ if (!connected) {
+
+ // Get hold of the data
+ try {
+ // resolve the URLs item to a property
+ Property property = Util.getProperty(getItem());
+ if (property == null) {
+ throw failure("connect",
+ "Multivalue property not supported", null);
+ }
+
+ // values to set later
+ String contentType;
+ String contentEncoding = null; // no defined content encoding
+ int contentLength = (int) property.getLength();
+ long lastModified;
+
+ Node parent = property.getParent();
+ if (parent.isNodeType("nt:resource")) {
+ lastModified = parent.getProperty("jcr:lastModified").getLong();
+ contentType = parent.getProperty("jcr:mimeType").getString();
+ if (parent.hasProperty("jcr:encoding")) {
+ contentEncoding =
+ parent.getProperty("jcr:encoding").getString();
+ }
+ } else {
+ lastModified = 0;
+ contentType = guessContentTypeFromName(getItem().getName());
+ if (contentType == null) {
+ contentType = (property.getType() == PropertyType.BINARY)
+ ? APPLICATION_OCTET
+ : TEXT_PLAIN;
+ }
+ }
+
+ log.debug("connect: Using atom '" + property.getPath() +
+ "' with content type '" + contentType + "' for " +
+ String.valueOf(contentLength) + " bytes");
+
+ // set the fields
+ setProperty(property);
+ setContentType(contentType);
+ setContentEncoding(contentEncoding);
+ setContentLength(contentLength);
+ setLastModified(lastModified);
+
+ // mark connection open
+ connected = true;
+
+ } catch (RepositoryException re) {
+ throw failure("connect", re.toString(), re);
+ }
+ }
+ }
+
+ /**
+ * Returns an input stream that reads from this open connection.
+ * <p>
+ * <b>NOTES:</b>
+ * <ul>
+ * <li>Each call to this method returns a new <code>InputStream</code>.
+ * <li>Do not forget to close the return stream when not used anymore for
+ * the system to be able to free resources.
+ * </ul>
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @throws IOException if an error occurrs opening the connection through
+ * {@link #connect()} or creating the <code>InputStream</code> on the
+ * repository <code>Property</code>.
+ *
+ * @see #connect()
+ */
+ public InputStream getInputStream() throws IOException {
+ try {
+ return getProperty().getStream();
+ } catch (RepositoryException re) {
+ throw failure("getInputStream", re.toString(), re);
+ }
+ }
+
+ /**
+ * Gets the named header field. This implementation only supports the
+ * Content-Type, Content-Encoding, Content-Length and Last-Modified header
+ * fields. All other names return <code>null</code>.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @param s The name of the header field value to return.
+ *
+ * @return The corresponding value or <code>null</code> if not one of the
+ * supported fields or the named field's value cannot be retrieved
+ * from the data source.
+ *
+ * @see #connect()
+ */
+ public String getHeaderField(String s) {
+ try {
+ connect();
+ if (CONTENT_LENGTH.equalsIgnoreCase(s)) {
+ return String.valueOf(contentLength);
+ } else if (CONTENT_TYPE.equalsIgnoreCase(s)) {
+ return contentType;
+ } else if (LAST_MODIFIED.equalsIgnoreCase(s)) {
+ return String.valueOf(lastModified);
+ } else if (CONTENT_ENCODING.equalsIgnoreCase(s)) {
+ return contentEncoding;
+ }
+ } catch (IOException ioe) {
+ log.info("getHeaderField: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the header field with the given index. As with
+ * {@link #getHeaderField(String)} only Content-Length, Content-Type,
+ * Content-Encoding, and Last-Modified are supported. All indexes other
+ * than 0, 1, 2 or 3 will return <code>null</code>.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @param i The index of the header field value to return.
+ *
+ * @return The corresponding value or <code>null</code> if not one of the
+ * supported fields or the known field's value cannot be retrieved
+ * from the data source.
+ *
+ * @see #connect()
+ */
+ public String getHeaderField(int i) {
+ try {
+ connect();
+ if (i == 0) {
+ return String.valueOf(contentLength);
+ } else if (i == 1) {
+ return contentType;
+ } else if (i == 2) {
+ return String.valueOf(lastModified);
+ } else if (i == 3) {
+ return contentEncoding;
+ }
+ } catch (IOException ioe) {
+ log.info("getHeaderField: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the name of the header field with the given index. As with
+ * {@link #getHeaderField(String)} only Content-Length, Content-Type,
+ * Content-Encoding and Last-Modified are supported. All indexes other than
+ * 0, 1, 2 or 3 will return <code>null</code>.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @param i The index of the header field name to return.
+ * @return The corresponding name or <code>null</code> if not one of the
+ * supported fields.
+ *
+ * @see #connect()
+ */
+ public String getHeaderFieldKey(int i) {
+ try {
+ connect();
+ if (i == 0) {
+ return CONTENT_LENGTH;
+ } else if (i == 1) {
+ return CONTENT_TYPE;
+ } else if (i == 2) {
+ return LAST_MODIFIED;
+ } else if (i == 3) {
+ return CONTENT_ENCODING;
+ }
+ } catch (IOException ioe) {
+ log
+ .info("getHeaderFieldKey: Problem connecting: "
+ + ioe.toString());
+ log.debug("dump", ioe);
+ }
+ return null;
+ }
+
+ /**
+ * Returns an unmodifiable map of all header fields. Each entry is indexed
+ * with a string key naming the field. The entry's value is an unmodifiable
+ * list of the string values of the respective header field.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @return An unmodifiable map of header fields and their values. The map
+ * will be empty if an error occurrs connecting through
+ * {@link #connect()}.
+ *
+ * @see #connect()
+ */
+ public Map getHeaderFields() {
+ Map fieldMap = new HashMap();
+
+ try {
+ connect();
+ fieldMap.put(CONTENT_LENGTH, toList(String.valueOf(contentLength)));
+ fieldMap.put(CONTENT_TYPE, toList(contentType));
+ fieldMap.put(LAST_MODIFIED, toList(String.valueOf(lastModified)));
+
+ // only include if not null))
+ if (contentEncoding != null) {
+ fieldMap.put(CONTENT_ENCODING, toList(contentEncoding));
+ }
+ } catch (IOException ioe) {
+ log.info("getHeaderFields: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+
+ return Collections.unmodifiableMap(fieldMap);
+ }
+
+ /**
+ * Returns the content type of the data as a string. This is just a
+ * perfomance convenience overwrite of the base class implementation.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @return The content length of the data or <code>null</code> if the
+ * content type cannot be derived from the data source.
+ *
+ * @see #connect()
+ */
+ public String getContentType() {
+ try {
+ connect();
+ return contentType;
+ } catch (IOException ioe) {
+ log.info("getContentType: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the content encoding of the data as a string. This is just a
+ * perfomance convenience overwrite of the base class implementation.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @return The content encoding of the data or <code>null</code> if the
+ * content encoding cannot be derived from the data source.
+ *
+ * @see #connect()
+ */
+ public String getContentEncoding() {
+ try {
+ connect();
+ return contentEncoding;
+ } catch (IOException ioe) {
+ log.info("getContentEncoding: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the content length of the data as an number. This is just a
+ * perfomance convenience overwrite of the base class implementation.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @return The content length of the data or -1 if the content length cannot
+ * be derived from the data source.
+ *
+ * @see #connect()
+ */
+ public int getContentLength() {
+ try {
+ connect();
+ return contentLength;
+ } catch (IOException ioe) {
+ log.info("getContentLength: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the value of the <code>last-modified</code> header field. The
+ * result is the number of milliseconds since January 1, 1970 GMT.
+ * <p>
+ * Calling this method implicitly calls {@link #connect()} to ensure the
+ * connection is open.
+ *
+ * @return the date the resource referenced by this
+ * <code>URLConnection</code> was last modified, or -1 if not
+ * known.
+ *
+ * @see #connect()
+ */
+ public long getLastModified() {
+ try {
+ connect();
+ return lastModified;
+ } catch (IOException ioe) {
+ log.info("getLastModified: Problem connecting: " + ioe.toString());
+ log.debug("dump", ioe);
+ }
+ 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 -----------------------------------------------------
+
+ /**
+ * Logs the message and returns an IOException to be thrown by the caller.
+ * The log message contains the caller name, the external URL form and the
+ * message while the IOException is only based on the external URL form and
+ * the message given.
+ *
+ * @param method The method in which the error occurred. This is used for
+ * logging.
+ * @param message The message to log and set in the exception
+ * @param cause The cause of failure. May be <code>null</code>.
+ *
+ * @return The IOException the caller may throw.
+ */
+ protected IOException failure(String method, String message, Throwable cause) {
+ log.info(method + ": URL: " + url.toExternalForm() + ", Reason: "
+ + message);
+
+ if (cause != null) {
+ log.debug("dump", cause);
+ }
+
+ IOException ioe = new IOException(url.toExternalForm() + ": " + message);
+ ioe.initCause(cause);
+ return ioe;
+ }
+
+ /**
+ * Returns an unmodifiable list containing just the given string value.
+ */
+ private List toList(String value) {
+ String[] values = { value };
+ List valueList = Arrays.asList(values);
+ return Collections.unmodifiableList(valueList);
+ }
+}
\ No newline at end of file
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLConnection.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLConnection.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLHandler.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLHandler.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLHandler.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.net;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+import javax.jcr.Session;
+
+/**
+ * The <code>JCRURLHandler</code> is the <code>URLStreamHandler</code> for
+ * JCR Repository URLs identified by the scheme <code>jcr</code>.
+ * <p>
+ * 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.jackrabbit.net.URLFactory}
+ * class.
+ * <p>
+ * This class is not intended to be subclassed or instantiated by clients.
+ *
+ * @author Felix Meschberger
+ * @version $Rev:$, $Date:$
+ *
+ * @see org.apache.jackrabbit.net.JCRURLConnection
+ * @see org.apache.jackrabbit.net.URLFactory
+ * @see org.apache.jackrabbit.net.URLFactory#createURL(Session, String)
+ */
+class JCRURLHandler extends URLStreamHandler {
+
+ /**
+ * The session used to create this handler, which is also used to open
+ * the connection object.
+ *
+ * @see #getSession()
+ */
+ private final Session session;
+
+ /**
+ * 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>.
+ *
+ * @throws NullPointerException if <code>session</code> is <code>null</code>.
+ */
+ JCRURLHandler(Session session) {
+ if (session == null) {
+ throw new NullPointerException("session");
+ }
+
+ this.session = session;
+ }
+
+ /**
+ * Returns the session supporting this handler.
+ */
+ Session getSession() {
+ return session;
+ }
+
+ //---------- URLStreamHandler abstracts ------------------------------------
+
+ /**
+ * Gets a connection object to connect to an JCR Repository URL.
+ *
+ * @param url The JCR Repository URL to connect to.
+ *
+ * @return An instance of the {@link JCRURLConnection} class.
+ *
+ * @see JCRURLConnection
+ */
+ protected URLConnection openConnection(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);
+ }
+}
\ No newline at end of file
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/JCRURLHandler.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/URLFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/URLFactory.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/URLFactory.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/URLFactory.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.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
+ * @version $Rev:$, $Date:$
+ */
+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));
+ }
+
+ /**
+ * Creates a new JCRJar URL for the given session, archive and entry.
+ *
+ * @param session The repository session providing access to the archive.
+ * @param path The absolute path to the archive. This must either be the
+ * property containing the archive or an item which resolves to such
+ * a property through its primary item chain. 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.
+ * @param entry The entry within the archive. If <code>null</code>, the URL
+ * provides access to the archive itself.
+ *
+ * @return The JCRJar URL
+ *
+ * @throws MalformedURLException If an error occurrs creating the
+ * <code>URL</code> instance.
+ */
+ public static URL createJarURL(Session session, String path, String entry)
+ throws MalformedURLException {
+
+ JCRJarURLHandler handler = new JCRJarURLHandler(session);
+ String file = createURL(session, path).toExternalForm();
+
+ // append entry spec if not null
+ if (entry != null) {
+ file += "!/" + entry;
+ }
+
+ return new URL(REPOSITORY_JAR_SCHEME, "", -1, file, handler);
+ }
+}
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/URLFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/main/java/org/apache/jackrabbit/net/URLFactory.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/main/resources/org/apache/jackrabbit/classloader/type.cnd
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/main/resources/org/apache/jackrabbit/classloader/type.cnd?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/main/resources/org/apache/jackrabbit/classloader/type.cnd (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/main/resources/org/apache/jackrabbit/classloader/type.cnd Wed Dec 21 06:13:56 2005
@@ -0,0 +1,41 @@
+/*
+ * The "type.cnd" file contains the (mixin) node type definition which is
+ * required by the ExpandingArchiveClassPathEntry class, which supports
+ * on-demand unpacking of JAR/ZIP archives for enhanced performances of class
+ * path access.
+ *
+ * NOTE: This file is read through a reader with encoding "ISO-8859-1".
+ *
+ * @author Felix Meschberger
+ * @version $Rev:$, $Date:$
+ * @see org.apache.jackrabbit.classloader.ExpandingArchiveClassPathEntry
+ * @see org.apache.jackrabbit.classloader.NodeTypeSupport
+ */
+
+// The "rep" namespace is expected to be present in the repository.
+// For Jackrabbit based repositories, this is true, for other repositories, we
+// present the namespace declaration here.
+// This declaration is inline with the Jackrabbit internal namespace declaration
+// for the "rep" namespace.
+<rep = 'internal'>
+<nt = 'http://www.jcp.org/jcr/nt/1.0'>
+
+// The node containing the JAR/ZIP archive is tagged with this mixin node
+// type to singal, that the archive has been unpacked into the subtree
+// rooted at the "rep:jarContents" child node.
+[rep:jarFile] mixin
+
+// The "rep:jarExpanded" property is set to the timestamp of the date/time at
+// which the JAR/ZIP archive has been expanded.
+- rep:jarExpanded (date)
+ mandatory copy
+
+// The "rep:jarContents" is the root node of the subtree into which the archive
+// is unpacked. There is no explicit type requirement for the type of this
+// node, except, that it must be allowed nodes of type "nt:file" and "nt:folder"
+// below. Unpacking the archive in the ExpandingArchiveClassPathEntry class
+// will create the "rep:jarContents" node as an nt:folder node and create files
+// and folders contained in the archive as "nt:file" and "nt:folder" nodes,
+// respectively.
++ rep:jarContents (nt:base) = nt:folder
+ mandatory copy
\ No newline at end of file
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/AbstractClassLoaderTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/AbstractClassLoaderTest.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/AbstractClassLoaderTest.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/AbstractClassLoaderTest.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.classloader;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.jcr.Credentials;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory;
+
+import com.sun.corba.se.ActivationIDL.Repository;
+import com.sun.org.omg.CORBA.ExcDescriptionSeqHelper;
+
+/**
+ * The <code>AbstractClassLoaderTest</code> TODO
+ *
+ * @author fmeschbe
+ * @version $Rev:$, $Date:$
+ */
+public class AbstractClassLoaderTest extends TestCase {
+
+ /** Logger for test cases */
+ protected static final Log log =
+ LogFactory.getLog("org.apache.jackrabbit.classloader.test");
+
+ protected static final String WORKSPACE = "default";
+ protected static final String USER = "admin";
+
+ protected static final String PROVIDER_URL = "ClassLoader";
+ protected static final String REPOSITORY_NAME = "ClassLoaderRepository";
+
+ protected RepositoryImpl repository;
+ protected Session session;
+
+ private Set createdItems = new HashSet();
+
+ public AbstractClassLoaderTest() {
+ super();
+ }
+
+ public AbstractClassLoaderTest(String name) {
+ super(name);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ if (!"repositoryStart".equals(getName())) {
+ Context ctx = getInitialContext();
+ repository = (RepositoryImpl) ctx.lookup(REPOSITORY_NAME);
+
+ Credentials creds = new SimpleCredentials(USER, USER.toCharArray());
+ session = repository.login(creds, WORKSPACE);
+ }
+ }
+
+ public void repositoryStart() throws Exception {
+ InputStream config = getClass().getResourceAsStream("/repository.xml");
+ String home = new File("cltest").getAbsolutePath();
+ RepositoryConfig rc = RepositoryConfig.create(config, home);
+ RepositoryImpl repository = RepositoryImpl.create(rc);
+
+ try {
+ Context ctx = getInitialContext();
+ ctx.bind(REPOSITORY_NAME, repository);
+ } catch (NamingException ne) {
+ repository.shutdown();
+ throw ne;
+ }
+ }
+
+ public void repositoryStop() throws Exception {
+ // this is special, logout here and clean repository
+ disconnect();
+
+ if (repository != null) {
+ repository.shutdown();
+ repository = null;
+ }
+
+ Context ctx = getInitialContext();
+ ctx.unbind(REPOSITORY_NAME);
+ }
+
+ protected void tearDown() throws Exception {
+ disconnect();
+ repository = null;
+ super.tearDown();
+ }
+
+ private Context getInitialContext() throws NamingException {
+ Hashtable env = new Hashtable();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ DummyInitialContextFactory.class.getName());
+ env.put(Context.PROVIDER_URL, PROVIDER_URL);
+
+ return new InitialContext(env);
+ }
+
+ private void disconnect() {
+ if (session != null) {
+ clearRepository(session);
+ session.logout();
+ session = null;
+ }
+ }
+
+ //---------- RepositoryLoader ----------------------------------------------
+
+ protected void loadRepository(Session session, InputStream ins) {
+ if (ins == null) {
+ ins = getClass().getResourceAsStream("/preload.properties");
+ if (ins == null) {
+ log.warn("Cannot find preload properties /preload.properties");
+ return;
+ }
+ }
+
+ List keys = new ArrayList();
+ Properties props = new Properties();
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(ins));
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+
+ // cut off line comment
+ int comment = line.indexOf('#');
+ if (comment >= 0) {
+ line = line.substring(0, comment);
+ }
+
+ // trim leading and trailing whitespace
+ line = line.trim();
+
+ // ignore line of empty
+ if (line.length() == 0) {
+ continue;
+ }
+
+ int sep = line.indexOf('=');
+ if (sep < 0) {
+ continue;
+ }
+
+ String key = line.substring(0, sep).trim();
+
+ StringBuffer buf = new StringBuffer(line.substring(sep+1).trim());
+
+ while (line.endsWith("\\")) {
+ // cut off last back slash
+ buf.setLength(buf.length()-1);
+
+ line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+
+ buf.append(line);
+ }
+
+ key = loadConvert(key);
+ String value = loadConvert(buf.toString());
+
+ keys.add(key);
+ props.setProperty(key, value);
+ }
+ } catch (IOException ioe) {
+ // ignore
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ignore) {}
+ }
+
+ try {
+ ins.close();
+ } catch (IOException ignore) {}
+ }
+
+ for (Iterator ki=keys.iterator(); ki.hasNext(); ) {
+ String path = (String) ki.next();
+ String config = props.getProperty(path);
+ StringTokenizer tokener = new StringTokenizer(config, ",");
+ if (!tokener.hasMoreTokens()) {
+ continue;
+ }
+
+ Node parent = null;
+ try {
+ parent = getParent(session, path);
+ } catch (RepositoryException re) {
+ log.warn("Cannot get parent of " + path, re);
+ }
+
+ if (parent == null) {
+ continue;
+ }
+
+ try {
+ String type = tokener.nextToken();
+ if ("n".equalsIgnoreCase(type)) {
+ loadNode(parent, getName(path), tokener);
+ createdItems.add(path);
+ } else if ("p".equalsIgnoreCase(type)) {
+ loadProperty(parent, getName(path), tokener);
+ }
+ } catch (RepositoryException re) {
+ log.warn("Cannot create item " + path, re);
+ }
+ }
+
+ try {
+ if (session.hasPendingChanges()) {
+ session.save();
+ }
+ } catch (RepositoryException re) {
+ log.warn("Cannot save session", re);
+ } finally {
+ try {
+ if (session.hasPendingChanges()) {
+ session.refresh(false);
+ }
+ } catch (RepositoryException re) {
+ log.warn("Cannot even refresh the session");
+ }
+ }
+ }
+
+ protected void clearRepository(Session session) {
+ for (Iterator ii=createdItems.iterator(); ii.hasNext(); ) {
+ String path = (String) ii.next();
+ try {
+ if (!session.itemExists(path)) {
+ continue;
+ }
+
+ session.getItem(path).remove();
+ } catch (RepositoryException re) {
+ log.info("Cannot remove Item " + path + ": " + re);
+ }
+ }
+
+ try {
+ session.save();
+ } catch (RepositoryException re) {
+ log.warn("Cannot save removals", re);
+ }
+
+ createdItems.clear();
+ }
+
+ private void loadNode(Node parent, String name,
+ StringTokenizer config) throws RepositoryException {
+
+ // node type
+ String primaryType;
+ if (config.hasMoreTokens()) {
+ primaryType = config.nextToken();
+ } else {
+ primaryType = "nt:unstructured";
+ }
+
+ Node node = parent.addNode(name, primaryType);
+
+ // content URL
+ if (config.hasMoreTokens()) {
+ String urlString = config.nextToken();
+ try {
+ URL url;
+ if (urlString.startsWith("classpath:")) {
+ urlString = urlString.substring("classpath:".length());
+ url = getClass().getResource(urlString);
+ } else {
+ url = new URL(urlString);
+ }
+ URLConnection connection = url.openConnection();
+ makeFileNode(node, connection);
+ } catch (IOException ioe) {
+ System.err.println(ioe);
+ }
+ }
+ }
+
+ private void loadProperty(Node parent, String name,
+ StringTokenizer config) throws RepositoryException {
+ String typeName;
+ if (config.hasMoreTokens()) {
+ typeName = config.nextToken();
+ } else {
+ typeName = "";
+ }
+ int type;
+ try {
+ type = PropertyType.valueFromName(typeName);
+ } catch (IllegalArgumentException iae) {
+ type = PropertyType.STRING;
+ }
+
+ String stringValue = ""; // default value
+ if (config.hasMoreTokens()) {
+ stringValue = config.nextToken();
+ }
+
+ /* Property prop = */ parent.setProperty(name, stringValue, type);
+ }
+
+ static void makeFileNode(Node node, URLConnection content)
+ throws RepositoryException {
+
+ Node contentNode = node.addNode("jcr:content", "nt:resource");
+ InputStream ins = null;
+ try {
+ ins = content.getInputStream();
+ contentNode.setProperty("jcr:data", ins);
+ } catch (IOException ioe) {
+ // ignore, but redefine content data
+ contentNode.setProperty("jcr:data", "mockdata", PropertyType.BINARY);
+ } finally {
+ if (ins != null) {
+ try {
+ ins.close();
+ } catch (IOException ioe) {}
+ }
+ }
+
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(content.getLastModified());
+ contentNode.setProperty("jcr:lastModified", cal);
+
+ String mimeType = content.getContentType();
+ if (mimeType == null || mimeType.toLowerCase().indexOf("unknown") >= 0) {
+ mimeType = URLConnection.guessContentTypeFromName(node.getName());
+ }
+ if (mimeType == null) {
+ mimeType = "application/octet-stream";
+ }
+ contentNode.setProperty("jcr:mimeType", mimeType);
+
+ String encoding = content.getContentEncoding();
+ if (encoding != null) {
+ contentNode.setProperty("jcr:encoding", encoding);
+ }
+ }
+
+ static Node getParent(Session session, String path)
+ throws RepositoryException {
+
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash < 0) {
+ return null;
+ }
+
+ String parentPath = path.substring(0, lastSlash);
+ if (parentPath.length() == 0) {
+ return session.getRootNode();
+ }
+
+ try {
+ Item item = session.getItem(parentPath);
+ if (item.isNode()) {
+ return (Node) item;
+ }
+ } catch (PathNotFoundException pnfe) {
+
+ // create the intermediate node as an unstructured node
+ Node parent = getParent(session, parentPath);
+ if (parent != null) {
+ lastSlash = parentPath.lastIndexOf('/');
+ if (lastSlash < 0) {
+ return null;
+ }
+ String name = parentPath.substring(lastSlash+1);
+
+ return parent.addNode(name, "nt:folder");
+ }
+ }
+
+ return null;
+ }
+
+ private String getName(String path) {
+ return path.substring(path.lastIndexOf('/')+1);
+ }
+
+ private String loadConvert(String theString) {
+ char aChar;
+ int len = theString.length();
+ StringBuffer outBuffer = new StringBuffer(len);
+
+ for (int x=0; x<len; ) {
+ aChar = theString.charAt(x++);
+ if (aChar == '\\') {
+ aChar = theString.charAt(x++);
+ if (aChar == 'u') {
+ // Read the xxxx
+ int value=0;
+ for (int i=0; i<4; i++) {
+ aChar = theString.charAt(x++);
+ switch (aChar) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ value = (value << 4) + aChar - '0';
+ break;
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ value = (value << 4) + 10 + aChar - 'a';
+ break;
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ value = (value << 4) + 10 + aChar - 'A';
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Malformed \\uxxxx encoding.");
+ }
+ }
+ outBuffer.append((char)value);
+ } else {
+ if (aChar == 't') aChar = '\t';
+ else if (aChar == 'r') aChar = '\r';
+ else if (aChar == 'n') aChar = '\n';
+ else if (aChar == 'f') aChar = '\f';
+ outBuffer.append(aChar);
+ }
+ } else
+ outBuffer.append(aChar);
+ }
+ return outBuffer.toString();
+ }
+}
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/AbstractClassLoaderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/AbstractClassLoaderTest.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/DynamicRepositoryClassLoaderTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/DynamicRepositoryClassLoaderTest.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/DynamicRepositoryClassLoaderTest.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/DynamicRepositoryClassLoaderTest.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.classloader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.apache.log4j.Logger;
+
+import sun.tools.jar.resources.jar_fr;
+
+/**
+ * The <code>DynamicRepositoryClassLoaderTest</code> class
+ *
+ * @author Felix Meschberger
+ */
+public class DynamicRepositoryClassLoaderTest extends AbstractClassLoaderTest {
+
+ private static final String CLASSES_FOLDER = "/node1/classes";
+ private static final String JAR_FILE = "/node1/mock.jar";
+ private static final String CLASS_FILE = "org/apache/jackrabbit/classloader/Util.class";
+ private static final String JAR_FILE_ENTRY = "mock/aDir/anotherFile.txt";
+ private static final String NON_EXISTING_JAR_FILE_ENTRY = "mock/aDir/missingFile.txt";
+
+ private static final String[] handles = { CLASSES_FOLDER, JAR_FILE };
+
+ private DynamicRepositoryClassLoader loader;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ loadRepository(session, null);
+
+ loader = new DynamicRepositoryClassLoader(session, handles, null);
+ }
+
+ protected void tearDown() throws Exception {
+ if (loader != null) {
+ loader.destroy();
+ loader = null;
+ }
+
+ super.tearDown();
+ }
+
+ public void testGetURLs() {
+ URL[] urls = loader.getURLs();
+
+ /*
+ * Expected URLs
+ * urls[0] = jcr:/_/default/node1/classes/
+ * urls[1] = jar:jcr:/_/default/node1/mock.jar
+ */
+
+ assertNotNull("Class loader URLs", urls);
+ assertEquals("Number of class path entries", handles.length, urls.length);
+ assertEquals("URL " + CLASSES_FOLDER, "jcr:/_/" + WORKSPACE + CLASSES_FOLDER + "/", urls[0].toString());
+ assertEquals("URL " + JAR_FILE, "jar:jcr:/_/" + WORKSPACE + JAR_FILE, urls[1].toString());
+ }
+
+ public void testClassFile() {
+ URL resource = loader.getResource(CLASS_FILE);
+ assertNotNull("Resource " + CLASS_FILE, resource);
+ }
+
+ public void testJarEntry() {
+ URL resource = loader.getResource(JAR_FILE_ENTRY);
+ assertNotNull("Resource " + JAR_FILE_ENTRY, resource);
+
+ resource = loader.getResource(NON_EXISTING_JAR_FILE_ENTRY);
+ assertNull("Resource " + NON_EXISTING_JAR_FILE_ENTRY + " not expected", resource);
+ }
+
+ public void testResources() throws IOException {
+ Enumeration res = loader.getResources(CLASS_FILE);
+ assertTrue("At least one resource " + CLASS_FILE, res.hasMoreElements());
+
+ URL url = (URL) res.nextElement();
+ assertNotNull(url);
+
+ assertFalse("Only expecint one resource " + CLASS_FILE, res.hasMoreElements());
+ }
+}
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/DynamicRepositoryClassLoaderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/DynamicRepositoryClassLoaderTest.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/ExpandingArchiveClassPathEntryTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/ExpandingArchiveClassPathEntryTest.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/ExpandingArchiveClassPathEntryTest.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/ExpandingArchiveClassPathEntryTest.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.classloader;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Date;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
+import org.apache.jackrabbit.util.Text;
+
+public class ExpandingArchiveClassPathEntryTest extends AbstractClassLoaderTest {
+
+ private static final String NODE_TYPE = "rep:jarFile";
+
+ private static final String ROOT = "/test";
+ private static final String JAR_PATH = ROOT + "/mock.jar";
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ if (session.itemExists(ROOT)) {
+ log.info("Removing old test root entry");
+ session.getItem(ROOT).remove();
+ session.save();
+ }
+ }
+
+ protected void tearDown() throws Exception {
+ if (session.itemExists(ROOT)) {
+ session.getItem(ROOT).remove();
+ session.save();
+ }
+
+ super.tearDown();
+ }
+
+ public void testCanExpand() throws RepositoryException {
+ // check for the node type - may or may not exist
+ try {
+ session.getWorkspace().getNodeTypeManager().getNodeType(NODE_TYPE);
+ log.info("Node type " + NODE_TYPE + " already registered");
+ } catch (NoSuchNodeTypeException nsoe) {
+ // expected behaviour
+ log.info("Node type " + NODE_TYPE + " not registered yet");
+ }
+
+ boolean canExpand = ExpandingArchiveClassPathEntry.canExpandArchives(session);
+ assertTrue("Expecting archives to be expandable", canExpand);
+
+ // check for the node type - must exist
+ session.getWorkspace().getNodeTypeManager().getNodeType(NODE_TYPE);
+ log.info("Node type " + NODE_TYPE + " already registered");
+ }
+
+ public void testExpand() throws IOException, RepositoryException {
+ URL url = getClass().getResource("/mock.jar");
+
+ Node parent = getParent(session, JAR_PATH);
+ Node jar = parent.addNode(Text.getName(JAR_PATH), "nt:file");
+ makeFileNode(jar, url.openConnection());
+ session.save();
+
+ Property prop = Util.getProperty(session.getItem(JAR_PATH));
+
+ ExpandingArchiveClassPathEntry pe =
+ new ExpandingArchiveClassPathEntry(prop, JAR_PATH);
+
+ ClassLoaderResource res = pe.getResource("mock/aDir/anotherFile.txt");
+ assertNotNull("anotherFile.txt expected to exist", res);
+
+ url = res.getURL();
+ assertNotNull("anotherFile's URL missing", url);
+
+ String data = new String(res.getBytes());
+ log.info("URL : " + url);
+ log.info("Path: " + res.getPath());
+ log.info("Prop: " + res.getProperty().getPath());
+ log.info("Data: '" + data + "'");
+ log.info("Size: " + res.getContentLength() + " (bytes: " + res.getBytes().length + ")");
+ log.info("Time: " + new Date(res.getLastModificationTime()));
+ }
+}
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/ExpandingArchiveClassPathEntryTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/ExpandingArchiveClassPathEntryTest.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/PatternPathTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/PatternPathTest.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/PatternPathTest.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/PatternPathTest.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.classloader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Credentials;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+/**
+ * The <code>PatternPathTest</code> class
+ *
+ * @author Felix Meschberger
+ */
+public class PatternPathTest extends AbstractClassLoaderTest {
+
+ private static final String DUMMY = "/dummy/classes";
+ private static final String[] patterns = {
+ "/apps|libs/*/classes",
+ "/*/classes", null, "", DUMMY, "/", "*", "|",
+ "/apps/developers/fmeschbe/lib/*.doc" };
+ private static final Set included;
+ private static final Set excluded;
+
+ static {
+ included = new HashSet();
+
+ // matches *
+ included.add("/apps");
+ included.add("/libs");
+ included.add("/jcr:system"); // Repository child node
+ included.add("/jcr:primaryType"); // Repository property
+
+ // matches "/"
+ included.add("/");
+
+ // matches: "/apps|libs/*/classes"
+ included.add("/apps/CFC/classes");
+ included.add("/apps/Forms/classes");
+ included.add("/apps/playground/classes");
+ included.add("/libs/CFC/classes");
+ included.add("/libs/Forms/classes");
+
+ // matches "/*/classes"
+ included.add(DUMMY);
+
+ // matches "/apps/developers/fmeschbe/lib/*.doc"
+ included.add("/apps/developers/fmeschbe/lib/test1.doc");
+ included.add("/apps/developers/fmeschbe/lib/other.doc");
+
+ excluded = new HashSet();
+ excluded.add("/apps/developers/fmeschbe/classes");
+ excluded.add("/libs/developers/fmeschbe/classes");
+
+ excluded.add("/apps/developers/fmeschbe/lib/readme.txt");
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ InputStream ins = getClass().getResourceAsStream("PatternPathTest.preload.properties");
+ if (ins != null) {
+ try {
+ loadRepository(session, ins);
+ } finally {
+ try {
+ ins.close();
+ } catch (IOException ignore) {}
+ }
+ }
+ }
+
+ protected void tearDown() throws Exception {
+ if (session != null) {
+ clearRepository(session);
+ session.logout();
+ session = null;
+ }
+
+ super.tearDown();
+ }
+
+ public void testCreation() {
+ PatternPath ppl = new PatternPath(session, patterns);
+
+ // check completeness
+ Set pplSet = new HashSet(Arrays.asList(ppl.getPath()));
+ for (int i=0; i < patterns.length; i++) {
+ String pattern = patterns[i];
+ if (pattern == null || pattern.length() == 0) {
+ assertFalse("Empty Entry must not be conained", pplSet.contains(pattern));
+ } else {
+ assertTrue("Non Empty Entry must be contained", pplSet.contains(pattern));
+ }
+ }
+ }
+
+ public void testExpandedPaths() throws RepositoryException {
+ PatternPath ppl = new PatternPath(session, patterns);
+
+ // expand the path
+ List paths = ppl.getExpandedPaths();
+
+ // check whether all expanded entries are expected
+ Set expected = new HashSet(included);
+ assertEquals("Number of path entries", expected.size(), paths.size());
+ for (Iterator pi=paths.iterator(); pi.hasNext(); ) {
+ String entry = (String) pi.next();
+ assertTrue("Unexpected path entry " + entry, expected.remove(entry));
+ }
+
+ // check whether the expected inclusions have all been in the expansion
+ assertTrue("Not all inclusions: " + expected, expected.isEmpty());
+
+ // check that no exlusions are included
+ for (Iterator pi=paths.iterator(); pi.hasNext(); ) {
+ String entry = (String) pi.next();
+ assertFalse("Path entry must be excluded" + entry, excluded.contains(entry));
+ }
+ }
+
+ public void testMatchPath() {
+ PatternPath ppl = new PatternPath(session, patterns);
+
+ // paths expected to match
+ for (Iterator ii=included.iterator(); ii.hasNext(); ) {
+ String path = (String) ii.next();
+ assertTrue("Expect Match: " + path, ppl.matchPath(path));
+ }
+
+ // paths expected to not match
+ for (Iterator ei=excluded.iterator(); ei.hasNext(); ) {
+ String path = (String) ei.next();
+ assertFalse("Unexpect Match: " + path, ppl.matchPath(path));
+ }
+ }
+}
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/PatternPathTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/PatternPathTest.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/TestAll.java?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/TestAll.java (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/TestAll.java Wed Dec 21 06:13:56 2005
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.jackrabbit.classloader;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class TestAll {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite("Test for Jackrabbit Class Loader");
+ //$JUnit-BEGIN$
+ suite.addTest(new AbstractClassLoaderTest("repositoryStart"));
+ suite.addTestSuite(PatternPathTest.class);
+ suite.addTestSuite(ExpandingArchiveClassPathEntryTest.class);
+ suite.addTestSuite(DynamicRepositoryClassLoaderTest.class);
+ suite.addTest(new AbstractClassLoaderTest("repositoryStop"));
+ //$JUnit-END$
+ return suite;
+ }
+}
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/TestAll.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/java/org/apache/jackrabbit/classloader/TestAll.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/log4j.properties?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/log4j.properties (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/log4j.properties Wed Dec 21 06:13:56 2005
@@ -0,0 +1,22 @@
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=INFO, file
+#log4j.rootLogger=DEBUG, stdout, file
+#log4j.rootLogger=ERROR, stdout, file
+
+log4j.logger.org.apache.jackrabbit.classloader.test=DEBUG
+
+# 'stdout' is set to be a ConsoleAppender.
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+
+# 'stdout' uses PatternLayout
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
+
+# 'file' is set to be a FileAppender.
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.File=jcr.log
+# log4j.appender.file.Append=false
+
+# 'file' uses PatternLayout.
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/log4j.properties
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/mock.jar
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/mock.jar?rev=358296&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/mock.jar
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/org/apache/jackrabbit/classloader/PatternPathTest.preload.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/org/apache/jackrabbit/classloader/PatternPathTest.preload.properties?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/org/apache/jackrabbit/classloader/PatternPathTest.preload.properties (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/org/apache/jackrabbit/classloader/PatternPathTest.preload.properties Wed Dec 21 06:13:56 2005
@@ -0,0 +1,60 @@
+#
+# Properties file to preload the MockRepository with content.
+# Each session created by the MockRepository upon calling login
+# reads this file to define a structure of content.
+#
+# Each property in this file defines a single item. The name
+# of the property is the absolute path to the item defined.
+# Order of the definitions in this file is relevant in that
+# intermediate nodes are automatically defined as
+# nt:unstructured nodes and may not be redefined later.
+#
+# The value of each property is a series of comma-separated
+# fields. The first field must either be "n" to indicate a
+# Node or "p" to indicate a Property. Any other values results
+# in the property being ignored for item creation. The remaining
+# fields depend on whether a Node or Property is defined.
+#
+# For nodes the fields are:
+# 1 - "n" to indicate the definition of a Node
+# 2 - The name of the node type, may be any string not
+# not containing a comma. The default value is
+# "nt:unstructured"
+# 3 - The name of the primary item. This may be missing
+# in which case there is no primary item or a well
+# known default value is used. For nt:file typed
+# nodes, the default is "jcr:content" for nt:resource
+# typed nodes, the default is "jcr:data"
+#
+# For Properties the fields are:
+# 1 - "p" to indicate the definition of a Property
+# 2 - The name of the property type. This must be one
+# of the type names defined in the PropertyType
+# class. If empty or or unknown, "String" is used
+# as the default.
+# 3 - The value of the property to the defined. The
+# value must be acceptable for the
+# ValueFactory.createValue(int type, String value)
+# method. If empty or missing, an empty string is
+# used as the property value, which may not be
+# acceptable for all property types.
+#
+# Property values (last field in the property definition) may
+# span multiple lines. Each line must be terminated with the
+# backslash character indicating the continuation of the line on
+# the next line of file.
+
+# various class path entries
+/apps/CFC/classes = n,nt:folder
+/apps/Forms/classes = n,nt:folder
+/apps/playground/classes = n,nt:folder
+
+/apps/developers/fmeschbe/classes = n,nt:folder
+
+/apps/developers/fmeschbe/lib/readme.txt = n,nt:file,classpath:/readme.txt
+/apps/developers/fmeschbe/lib/test1.doc = n,nt:file,classpath:/test1.txt
+/apps/developers/fmeschbe/lib/other.doc = n,nt:file,classpath:/other.txt
+
+/libs/CFC/classes = n,nt:folder
+/libs/Forms/classes = n,nt:folder
+/libs/developers/fmeschbe/classes = n,nt:folder
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/org/apache/jackrabbit/classloader/PatternPathTest.preload.properties
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/other.txt
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/other.txt?rev=358296&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/other.txt (added)
+++ incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/other.txt Wed Dec 21 06:13:56 2005
@@ -0,0 +1 @@
+Some Test for other.doc
\ No newline at end of file
Propchange: incubator/jackrabbit/trunk/contrib/classloader/src/test/resources/other.txt
------------------------------------------------------------------------------
svn:eol-style = native