Index: docs/gettingstarted/src/main/docbook/en-US/content/using_modeshape.xml
===================================================================
--- docs/gettingstarted/src/main/docbook/en-US/content/using_modeshape.xml (revision 1859)
+++ docs/gettingstarted/src/main/docbook/en-US/content/using_modeshape.xml (working copy)
@@ -30,56 +30,39 @@
]>
Using ModeShape
- Using ModeShape within your application is actually quite straightforward. As you'll see in this chapter,
- the first step is setting up ModeShape and starting the JcrEngine. After that, you obtain the
- javax.jcr.Repository instance for a named repository and just use the standard JCR API throughout your
- application.
+ Using ModeShape within your application is actually quite straightforward. Although there are multiple ways to
+ access a JCR repository in ModeShape, the simplest is to use the JSR-283 &RepositoryFactory; interface to
+ get a reference to a named javax.jcr.Repository from a configuration file. After that, you just use
+ the standard JCR API throughout your application.
-
- ModeShape's JcrEngine
+
+ ModeShape's JcrRepositoryFactory
- ModeShape encapsulates everything necessary to run one or more JCR repositories into a single &JcrEngine; instance.
- This includes all underlying repository sources, the pools of connections to the sources, the sequencers,
- the MIME type detector(s), and the &Repository; implementations.
+ ModeShape provides an implementation of the &RepositoryFactory; interface that can return a reference to a named repository
+ based on a provided configuration file. The code to get started with this is very simple.
+
- Obtaining a &JcrEngine; instance is very easy - assuming that you have a valid &JcrConfiguration; instance. We'll see
- how to get one of those in a little bit, but if you have one then all you have to do is build and start the engine:
-
-
-
- Obtaining a JCR &Repository; instance is a matter of simply asking the engine for it by the name defined in the configuration:
-
-
-
- At this point, your application can proceed by working with the JCR API.
-
-
- And, once you're finished with the &JcrEngine;, you should shut it down:
-
-
-
- When the shutdown() method is called, the &Repository; instances managed by the engine are marked as being shut down,
- and they will not be able to create new &Session;s. However, any existing &Session;s or ongoing operations (e.g., event notifications)
- present at the time of the shutdown() call will be allowed to finish.
- In essence, shutdown() is a graceful request, and since it may take some time to complete,
- you can wait until the shutdown has completed by simply calling awaitTermination(...) as shown above.
- This method will block until the engine has indeed shutdown or until the supplied time duration has passed (whichever comes first).
- And, yes, you can call the awaitTermination(...) method repeatedly if needed.
+ The simplest format for the configuration URL in the listing above is file:relativePathToConfigFile?repositoryName=yourRepositoryName. In this example,
+ the configuration file that specifies the repository setup will be loaded from the file path relativePathToConfigFile and the repository named yourRepositoryName
+ will be returned. If there is no repository with that name or the configuration file does not exist at that path, getRepository(Map) will return null.
-
+
- JcrConfiguration
+ ModeShape Configuration Files
- The previous section assumed the existence of a &JcrConfiguration;. Obtaining an instance isn't very difficult at all.
- In fact, there's only one no-argument constructor, so actually creating the instance is a piece of cake.
- It can be a little more challenging to assemble the configuration you want to use.
+ The previous section assumed the existence of a configuration file. Creating a configuration file isn't very difficult at all.
- Each &JcrConfiguration; instance defines all of the components that will run inside the &JcrEngine;:
+ Each configuration file defines the components that are used to create the repository:
Repository sources are the POJO objects that each describe a particular
@@ -92,8 +75,8 @@ engine.awaitTermination(3,TimeUnit.SECONDS); // optional]]>
Repositories define the JCR repositories that are available. Each
- repository has a unique name that is used to obtain the &Repository; instance from the &JcrEngine;'s getRepository(String)
- method, but each repository definition also can include the predefined namespaces (other than those automatically defined by
+ repository has a unique name that is used to obtain the &Repository; instance,
+ but each repository definition also can include the predefined namespaces (other than those automatically defined by
ModeShape), various options, and the node types that are to be available in the repository without explicit registration
through the JCR API.
@@ -113,52 +96,10 @@ engine.awaitTermination(3,TimeUnit.SECONDS); // optional]]>
-
- There really are three options for setting up a &JcrConfiguration; instance:
-
-
- Loading from a file is conceptually the easiest and requires the least amount
- of Java code, but it does require a configuration file. More on that in a bit.
-
-
- Loading from a configuration repository is not much more complicated than loading
- from a file, but it does allow multiple &JcrEngine; instances (usually in different processes perhaps on different machines)
- to easily access a shared, persistent configuration. And technically, loading the configuration from a file really just
- imports the configuration file into a transient &InMemoryRepositorySource;.
-
-
- Programmatic configuration is always possible, even if the configuration is loaded
- from a file or repository. Using the &JcrConfiguration;'s API, you can define (or update or remove) all of the definitions that make
- up a configuration.
-
-
-
-
- Each of these approaches has their obvious advantages, so the choice of which one to use is entirely up to you.
-
-
- Loading from a configuration file
-
- Loading the ModeShape configuration from a file is actually very simple:
-
-
-
- where the file parameter can actually be a &File; instance, a &URL; to the file, an &InputStream;
- containing the contents of the file, or even a &String; containing the path to the file.
-
-
- The loadFrom(...) methods can be called multiple times, but each time it completely wipes
- out any current notion of the configuration and replaces it with the configuration found in the file.
-
-
-
- There is an optional second parameter that defines the &Path; within the configuration file identifying the parent node of the various
- configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
- at a different location in the hierarchical structure. (This is not often required, but when it is required
- this second parameter is very useful.)
-
+
+ Creating a configuration file
+ Creating a ModeShape configuration file is fairly straightforward.
Here is the configuration file that is used in the repository example, though it has been simplified a bit and most comments
have been removed for clarity):
@@ -223,150 +164,19 @@ configuration.loadFrom(file);]]>
]]>
-
- Loading from a configuration repository
-
- Loading the ModeShape configuration from an existing repository is also pretty straightforward. Simply create and configure the
- &RepositorySource; instance to point to the desired repository, and then call the loadFrom(&RepositorySource; source)
- method:
-
-
-
- This really is a more advanced way to define your configuration, so we won't go into how you configure a &RepositorySource;.
- Suffice to say that you can create a &JcrConfiguration; that uses a &RepositorySource;, programmatically define the configuration,
- and call save() on the &JcrConfiguration; to store the configuration in the repository sources. To use that
- configuration, just create &JcrConfiguration; objects using a &RepositorySource; pointed to the same persistent store,
- and you're done. For more information, consult the &ReferenceGuide;.
-
-
- If you use the loadFrom(&RepositorySource;,&Path;) form, you can control where the configuration content is
- stored in the repository. This is useful if you want to store multiple configurations in the same repository.
-
-
-
- Programmatic configuration
-
- Defining the configuration programmatically is not terribly complicated, and it for obvious reasons results in more verbose Java code.
- But this approach is very useful and often the easiest approach when the configuration must change or is a reflection of other
- dynamic information.
-
-
- The &JcrConfiguration; class was designed to have an easy-to-use API that makes it easy to configure each of the different kinds of
- components, especially when using an IDE with code completion. Here are several examples:
-
-
- Repository sources
- Each repository source definition must include the name of the &RepositorySource; class as well as each bean property
- that should be set on the object:
-
-
-
- This example defines an in-memory source with the name "source A", a description, and a single "defaultWorkspaceName" bean property.
- Different &RepositorySource; implementations will the bean properties that are required and optional.
- Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
- the classpath or from a specific classpath).
-
-
- Each time repositorySource(String) is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call remove()
- on the result of repositorySource(String).
- The set of existing definitions can be accessed with the repositorySources() method.
-
-
-
-
- Repositories
- Each repository must be defined to use a named repository source, but all other aspects (e.g., namespaces, node types, options)
- are optional.
-
-
- This example defines a repository that uses the "source 1" repository source (which could be a federated source, an in-memory source,
- a database store, or any other source). Additionally, this example adds the node types in the "myCustomNodeTypes.cnd" file as those
- that will be made available when the repository is accessed. It also defines the "http://www.example.com/acme" namespace,
- and finally sets the "JAAS_LOGIN_CONFIG_NAME" option to define the name of the JAAS login configuration that should be used by
- the ModeShape repository.
-
-
-
- Sequencers
- Each defined sequencer must specify the name of the &StreamSequencer; implementation class as well as the path expressions
- defining which nodes should be sequenced and the output paths defining where the sequencer output should be placed (often as a function
- of the input path expression).
-
-
- This shows an example of a sequencer definition named "Image Sequencer" that uses the &ImageMetadataSequencer; class
- (loaded from the classpath), that is to sequence the "jcr:data" property on any new or changed nodes that are named
- "jcr:content" below a parent node with a name ending in ".jpg", ".jpeg", ".gif", ".bmp", ".pcx", ".iff", ".ras",
- ".pbm", ".pgm", ".ppm" or ".psd". The output of the sequencing operation should be placed at the "/images/$1" node,
- where the "$1" value is captured as the name of the parent node. (The capture groups work the same was as regular expressions;
- see the &ReferenceGuide; for more details.)
- Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
- the classpath or from a specific classpath).
-
-
- Each time sequencer(String) is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call remove()
- on the result of sequencer(String).
- The set of existing definitions can be accessed with the sequencers() method.
-
-
-
-
- MIME type detectors
- Each defined MIME type detector must specify the name of the &MimeTypeDetector; implementation class as well as any
- other bean properties required by the implementation.
-
-
- Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
- the classpath or from a specific classpath).
-
-
- Each time mimeTypeDetector(String) is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call remove()
- on the result of mimeTypeDetector(String).
- The set of existing definitions can be accessed with the mimeTypeDetectors() method.
-
-
-
- Deploying ModeShape via JNDI
- Sometimes your applications can simply define a &JcrConfiguration; and instantiate the &JcrEngine; instance directly.
- This is very straightforward, and this is what the ModeShape examples do.
+ Sometimes your applications can simply define a configuration file and use the &JcrRepositoryFactory; to manage
+ the repository instances.
+ This is very straightforward, and this is useful for many simple applications.
Web applications are a different story. Often, you may not want your web application to contain the code that initializes
- a ModeShape engine. Or, you may want the same &JcrEngine; instance to be reused in multiple web applications deployed
+ a ModeShape JCR repository. Or, you may want the same repository instance to be reused in multiple web applications deployed
to the same web/application server. In these cases, it is possible to configure the web/app server's JNDI instance to
- instantiate the &JcrEngine;, meaning the web applications need only use the standard JNDI and JCR APIs.
+ instantiate the repository, meaning the web applications need only use the standard JNDI and JCR APIs.
Example application using JCR and JNDI
@@ -418,7 +228,7 @@ try {
repositoryName is the name of a JCR repository that exists
- in the &JcrConfiguration; and that will be made available by this JNDI entry
+ in the JCR configuration and that will be made available by this JNDI entry
@@ -540,8 +350,8 @@ try {
]]>
- Then, continue by defining a &JcrConfiguration; and building the engine, as discussed earlier.
- This is very straightforward, and this is exactly what the ModeShape examples do.
+ Then, continue by defining a configuration file and using the &JcrRepositoryFactory; to access the defined repositories, as discussed earlier.
+ This is very straightforward, and this is similar to what the ModeShape examples do.
Index: docs/gettingstarted/src/main/docbook/en-US/custom.dtd
===================================================================
--- docs/gettingstarted/src/main/docbook/en-US/custom.dtd (revision 1859)
+++ docs/gettingstarted/src/main/docbook/en-US/custom.dtd (working copy)
@@ -53,6 +53,7 @@
Repository">
+RepositoryFactory">
Session">
Credentials">
SimpleCredentials">
@@ -129,6 +130,7 @@
JcrEngine">
JcrConfiguration">
JcrRepository">
+JcrRepositoryFactory">
JcrSession">
JndiRepositoryFactory">
Index: docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml
===================================================================
--- docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml (revision 1859)
+++ docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml (working copy)
@@ -33,7 +33,8 @@
Using ModeShape within your application is actually quite straightforward. As you'll see in this chapter,
the first step is setting up ModeShape and starting the JcrEngine. After that, you obtain the
javax.jcr.Repository instance for a named repository and just use the standard JCR API throughout your
- application.
+ application. Alternatively, you can use the ModeShape implementation of the &RepositoryFactory; interface to access
+ your repository.
ModeShape's JcrEngine
@@ -412,6 +413,103 @@ configuration.storeTo(pathToFile);
+
+ JcrRepositoryFactory
+
+ ModeShape provides the &JcrRepositoryFactory; class, an implementation of the &RepositoryFactory; interface, that can return a reference to a named repository
+ based on a provided configuration file. In addition to providing the getRepository(Map) method from the
+ JSR-283 API, ModeShape also provides an extended API for this class in the org.modeshape.jcr.api.RepositoryFactory interface.
+
+
+ Accessing Repositories from Configuration Files
+
+ The simplest way to use the &JcrRepositoryFactory; to access a &Repository; is to provide it a URL that points to a configuration file.
+ This can be done with the following sample code:
+
+
+
+ Alternatively, if you know that you will be using ModeShape as your JCR API in the future and want to condense code at the expense of tighter coupling, you can
+ instantiate a &JcrRepositoryFactory; directly.
+
+
+
+ The value of configUrl in the code snippets above would be something like file:relativePathToConfigFile?repositoryName=yourRepositoryName.
+ In this example, the configuration file that specifies the repository setup will be loaded from the file path relativePathToConfigFile and
+ the repository named yourRepositoryName will be returned. If there is no repository with that name or the configuration file does not exist
+ at that path, getRepository(Map) will return null. The format for the configuration file is the same as used above
+ when loading a &JcrConfiguration; object from a configuration file.
+
+
+ If an absolute path to the configuration file works better, a value for configUrl like file:///absolutePathToConfigFile?repositoryName=yourRepositoryName
+ could have been used instead. Note the addition of the three forward slashes after the protocol portion of the URL (i.e., file:). this indicates that the
+ following path is an absolute path.
+
+
+ This method can be used to load files from the file system or from the classpath. If there is no file found at the given path, the same path will be used to try
+ to load the configuration file as a resource through the classloader.
+
+
+ Behind the scenes, the &JcrRepositoryFactory; is checking to see if it has already configured and started a &JcrEngine; for the named configuration file. If it
+ has already created a &JcrEngine; for this configuration, then that &JcrEngine; is reused. Otherwise, a new &JcrEngine; is created and configured based on the given
+ configuration file. Either way, the &JcrEngine; is used to get the reference to the returned &Repository;.
+
+
+
+ Accessing Repositories from JNDI
+
+ Given a slightly different URL, the same code used above can be reused to get a &Repository; from a &JcrEngine; that has been previously deployed through JNDI.
+ JNDI URLs take the form jndi:///nameOfJndiResource?repositoryName=yourRepositoryName. The nameOfJndiResource is passed directly to
+ a JNDI lookup. If no &JcrEngine; exists at the given name, the getRepository(Map) method will return null. Also, any additional
+ parameters besides JcrRepositoryFactory.URL that are provided in the parameters map in the getRepository(Map) method will be used
+ in the constructor for the InitialContext used to look up the JNDI reference.
+
+
+ Accessing a repository through JNDI differs slightly from accessing a repository from a configuration file in that the &JcrRepositoryFactory; will never create a
+ new &JcrEngine; instance in response to a getRepository invocation with a JNDI URL.
+
+
+
+ Cleaning Up after JcrRepositoryFactory
+
+ As a preceding section notes, it is possible for the &JcrRepositoryFactory; to create one or more &JcrEngine; instances. Although the
+ JSR-283 specification does not specify a way to shutdown engines or repositories created as a side effect of &JcrRepositoryFactory; use, ModeShape has an extension to the
+ JSR-283 API that provides this capability.
+
+
+
+ The code listed above will instantiate a new JcrRepositoryFactory and use a ModeShape-specific method to shutdown any &JcrEngine;s created by &JcrRepositoryFactory;
+ and wait for up to 30 seconds for each of them to shutdown gracefully. Behind the scenes, the shutdown(long, TimeUnit) method is iterating over an internal
+ collection of &JcrEngine;s and calling shutdown and awaitTermination(long, TimeUnit) on each engine.
+
+
+
+
Deploying ModeShape via JNDI
@@ -436,7 +534,8 @@ try {
// Look up the JCR Repository object ...
InitialContext initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
- Repository repo = (Repository) envCtx.lookup("jcr/local"); // name in JNDI is defined by configuration
+ // name in JNDI is defined by configuration
+ Repository repo = (Repository) envCtx.lookup("jcr/local");
// Obtain a JCR Session using simple authentication
// (or use anonymous authentication if desired)
Index: docs/reference/src/main/docbook/en-US/custom.dtd
===================================================================
--- docs/reference/src/main/docbook/en-US/custom.dtd (revision 1859)
+++ docs/reference/src/main/docbook/en-US/custom.dtd (working copy)
@@ -74,6 +74,7 @@
Repository">
+RepositoryFactory">
Session">
Credentials">
SimpleCredentials">
@@ -211,6 +212,7 @@
JcrEngine">
JcrConfiguration">
JcrRepository">
+JcrRepositoryFactory">
JcrSession">
JndiRepositoryFactory">
SecurityContextCredentials">
Index: modeshape-graph/src/main/java/org/modeshape/graph/GraphI18n.java
===================================================================
--- modeshape-graph/src/main/java/org/modeshape/graph/GraphI18n.java (revision 1859)
+++ modeshape-graph/src/main/java/org/modeshape/graph/GraphI18n.java (working copy)
@@ -47,8 +47,6 @@ public final class GraphI18n {
public static I18n pathIsAlreadyAbsolute;
public static I18n pathIsNotAbsolute;
public static I18n pathIsNotRelative;
- public static I18n identifierPathContainedUnsupportedIdentifierFormat;
- public static I18n identifierPathDoesNotMatchSuppliedUuid;
public static I18n unableToResolvePathRelativeToIdentifierPath;
public static I18n unableToCreateRelativePathWithIdentifierSegment;
public static I18n unableToCreatePathBasedUponIdentifierPath;
Index: modeshape-graph/src/main/java/org/modeshape/graph/Location.java
===================================================================
--- modeshape-graph/src/main/java/org/modeshape/graph/Location.java (revision 1859)
+++ modeshape-graph/src/main/java/org/modeshape/graph/Location.java (working copy)
@@ -40,7 +40,6 @@ import org.modeshape.graph.property.Name;
import org.modeshape.graph.property.NamespaceRegistry;
import org.modeshape.graph.property.Path;
import org.modeshape.graph.property.Property;
-import org.modeshape.graph.property.Path.Segment;
/**
* The location of a node, as specified by either its path, UUID, and/or identification properties. Hash codes are not implemented
@@ -102,26 +101,9 @@ public abstract class Location implements Iterable, Comparable, Comparable, Comparable implements Uuid
* {@inheritDoc}
*/
public UUID create( Path value ) {
- if (value.isIdentifier()) {
- // Get the identifier segment ...
- Segment segment = value.getLastSegment();
- assert segment.isIdentifier();
- try {
- // The local part of the segment's name should be the identifier, though it may not be a UUID ...
- String id = segment.getName().getLocalName();
- return UUID.fromString(id);
- } catch (IllegalArgumentException err) {
- throw new ValueFormatException(value, PropertyType.UUID,
- GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
- Path.class.getSimpleName(),
- value));
- }
- }
throw new ValueFormatException(value, PropertyType.UUID, GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
Path.class.getSimpleName(),
value));
Index: modeshape-graph/src/main/java/org/modeshape/graph/search/SearchEngineIndexer.java
===================================================================
--- modeshape-graph/src/main/java/org/modeshape/graph/search/SearchEngineIndexer.java (revision 1859)
+++ modeshape-graph/src/main/java/org/modeshape/graph/search/SearchEngineIndexer.java (working copy)
@@ -35,11 +35,11 @@ import org.modeshape.common.i18n.I18n;
import org.modeshape.common.util.CheckArg;
import org.modeshape.common.util.Logger;
import org.modeshape.common.util.NamedThreadFactory;
+import org.modeshape.graph.ModeShapeLexicon;
import org.modeshape.graph.ExecutionContext;
import org.modeshape.graph.GraphI18n;
import org.modeshape.graph.JcrLexicon;
import org.modeshape.graph.Location;
-import org.modeshape.graph.ModeShapeLexicon;
import org.modeshape.graph.connector.RepositoryConnectionFactory;
import org.modeshape.graph.connector.RepositorySourceException;
import org.modeshape.graph.property.InvalidPathException;
Index: modeshape-graph/src/main/java/org/modeshape/graph/session/GraphSession.java
===================================================================
--- modeshape-graph/src/main/java/org/modeshape/graph/session/GraphSession.java (revision 1859)
+++ modeshape-graph/src/main/java/org/modeshape/graph/session/GraphSession.java (working copy)
@@ -324,7 +324,6 @@ public class GraphSession {
*/
public Node findNodeWith( Path path ) throws PathNotFoundException, AccessControlException {
if (path.isRoot()) return getRoot();
- if (path.isIdentifier()) return findNodeWith(Location.create(path));
return findNodeRelativeTo(root, path.relativeTo(root.getPath()), true);
}
@@ -344,7 +343,6 @@ public class GraphSession {
boolean loadIfRequired )
throws PathNotFoundException, AccessControlException {
if (path.isRoot()) return getRoot();
- if (path.isIdentifier()) return findNodeWith(Location.create(path));
return findNodeRelativeTo(root, path.relativeTo(root.getPath()), loadIfRequired);
}
Index: modeshape-graph/src/main/resources/org/modeshape/graph/GraphI18n.properties
===================================================================
--- modeshape-graph/src/main/resources/org/modeshape/graph/GraphI18n.properties (revision 1859)
+++ modeshape-graph/src/main/resources/org/modeshape/graph/GraphI18n.properties (working copy)
@@ -35,8 +35,6 @@ pathCannotBeNormalized = The path {0} is invalid and cannot be normalized
pathIsAlreadyAbsolute = The path {0} is already an absolute path
pathIsNotAbsolute = The path {0} is not an absolute path
pathIsNotRelative = The path {0} is not a relative path
-identifierPathContainedUnsupportedIdentifierFormat = The identifier path "{0}" does not contain a known identifier format
-identifierPathDoesNotMatchSuppliedUuid = The identifier path "{0}" does not match the supplied UUID "{1}"
unableToResolvePathRelativeToIdentifierPath = Unable to resolve the path '{0}' relative to the identifier path '{1}'
unableToCreateRelativePathWithIdentifierSegment = Unable to create a relative path using one or more identifier segments: '{0}'. Identifier paths are always absolute.
unableToCreatePathBasedUponIdentifierPath = Unable to create a path using the identifier path '{0}' as the parent and the segment: '{1}'. Identifier paths may only contain a single identifier segment.
Index: modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/RepositoryFactory.java
new file mode 100644
===================================================================
--- /dev/null (revision 1859)
+++ modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/RepositoryFactory.java (working copy)
@@ -0,0 +1,58 @@
+package org.modeshape.jcr.api;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public interface RepositoryFactory {
+
+ public javax.jcr.Repository getRepository( Map parameters );
+
+ /**
+ * Begin the shutdown process for all the {@code JcrEngine JcrEngines} created by calls to {@link #getRepository(Map)}.
+ *
+ * Calling {@code #getRepository(Map)} with a file-based URL parameter causes a new {@code JcrEngine} to be instantiated and
+ * started. Any {@code JcrEngine} created in this manner must be stored by the {@code RepositoryFactory} implementation.
+ * Invoking this method iteratively invokes the {@code shutdown()} method on each {@code JcrEngine}.
+ *
+ *
+ * This method merely initiates the shutdown process for each {@code JcrEngine}. There is no guarantee that the shutdown
+ * process will have completed prior to this method returning. The {@link #shutdown(long, TimeUnit)} method provides the
+ * ability to wait until all engines are shutdown or the given time elapses.
+ *
+ *
+ * Invoking this method does not preclude creating new {@code JcrEngines} with future calls to {@link #getRepository(Map)}.
+ * Any caller using this method as part of an application shutdown process should take care to cease invocations of
+ * {@link #getRepository(Map)} prior to invoking this method.
+ *
+ */
+ public void shutdown();
+
+ /**
+ * Begin the shutdown process for all the {@code JcrEngine JcrEngines} created by calls to {@link #getRepository(Map)}.
+ *
+ * Calling {@code #getRepository(Map)} with a file-based URL parameter causes a new {@code JcrEngine} to be instantiated and
+ * started. Any {@code JcrEngine} created in this manner must be stored by the {@code RepositoryFactory} implementation.
+ * Invoking this method iteratively invokes the {@code shutdown()} method on each {@code JcrEngine} and then iteratively
+ * invokes the {@code awaitTermination(long, TimeUnit)} method to await termination.
+ *
+ *
+ * Although this method initiates the shutdown process for each {@code JcrEngine} and invokes the {@code awaitTermination}
+ * method, there is still no guarantee that the shutdown process will have completed prior to this method returning. It is
+ * possible for the time required to shutdown one or more of the engines to exceed the provided time window.
+ *
+ *
+ * Invoking this method does not preclude creating new {@code JcrEngines} with future calls to {@link #getRepository(Map)}.
+ * Any caller using this method as part of an application shutdown process should take care to cease invocations of
+ * {@link #getRepository(Map)} prior to invoking this method.
+ *
+ *
+ * @param timeout the maximum time per engine to allow for shutdown
+ * @param unit the time unit of the timeout argument
+ * @return true if all engines completely shut down and false if the timeout elapsed before it was shut down
+ * completely
+ * @throws InterruptedException if interrupted while waiting
+ */
+ public boolean shutdown( long timeout,
+ TimeUnit unit ) throws InterruptedException;
+
+}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrNode.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrNode.java (revision 1859)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrNode.java (working copy)
@@ -210,12 +210,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
return isNodeType(JcrMixLexicon.LOCKABLE);
}
- /**
- * Get the UUID of this node, regardless of whether this node is referenceable.
- *
- * @return the UUID of this node; never null
- * @throws RepositoryException if there is an error accessing the UUID of the node
- */
UUID uuid() throws RepositoryException {
PropertyInfo uuidProp = nodeInfo().getProperty(JcrLexicon.UUID);
if (uuidProp == null) {
@@ -227,26 +221,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
}
/**
- * Get the JCR 2.0-compatible identifier of this node, regardless of whether this node is referenceable.
- *
- * @return the JCR 2.0 identifier of this node; never null
- * @throws RepositoryException if there is an error accessing the identifier of the node
- */
- String identifier() throws RepositoryException {
- return uuid().toString();
- }
-
- /**
- * Get the absolute and normalized identifier path for this node, regardless of whether this node is referenceable.
- *
- * @return the node's identifier path; never null
- * @throws RepositoryException if there is an error accessing the identifier of this node
- */
- String identifierPath() throws RepositoryException {
- return "[" + uuid() + "]";
- }
-
- /**
* {@inheritDoc}
*
* @see javax.jcr.Node#getUUID()
@@ -451,7 +425,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
public final boolean hasProperty( String relativePath ) throws RepositoryException {
CheckArg.isNotEmpty(relativePath, "relativePath");
checkSession();
- if (relativePath.indexOf('/') >= 0 || relativePath.startsWith("[")) {
+ if (relativePath.indexOf('/') >= 0) {
try {
getProperty(relativePath);
return true;
@@ -553,14 +527,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
// Execute a query that will report all nodes referencing this node ...
String uuid = getUUID();
QueryBuilder builder = new QueryBuilder(context().getValueFactories().getTypeSystem());
- QueryCommand query = builder.select("jcr:primaryType")
- .fromAllNodesAs("allNodes")
- .where()
- .referenceValue("allNodes")
- .isEqualTo(uuid)
- .end()
- .limit(maxNumberOfNodes)
- .query();
+ QueryCommand query = builder.select("jcr:primaryType").fromAllNodesAs("allNodes").where().referenceValue("allNodes").isEqualTo(uuid).end().limit(maxNumberOfNodes).query();
Query jcrQuery = session().workspace().queryManager().createQuery(query);
QueryResult result = jcrQuery.execute();
return result.getNodes();
@@ -677,7 +644,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
CheckArg.isNotEmpty(relativePath, "relativePath");
checkSession();
int indexOfFirstSlash = relativePath.indexOf('/');
- if (indexOfFirstSlash == 0 || relativePath.startsWith("[")) {
+ if (indexOfFirstSlash == 0) {
// Not a relative path ...
throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
}
@@ -685,7 +652,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (indexOfFirstSlash != -1) {
// We know it's a relative path with more than one segment ...
Path path = pathFrom(relativePath).getNormalizedPath();
- assert !path.isIdentifier();
if (path.size() > 1) {
try {
AbstractJcrItem item = cache.findJcrItem(nodeId, location.getPath(), path);
@@ -722,7 +688,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (relativePath.equals(".")) return true;
if (relativePath.equals("..")) return isRoot() ? false : true;
int indexOfFirstSlash = relativePath.indexOf('/');
- if (indexOfFirstSlash == 0 || relativePath.startsWith("[")) {
+ if (indexOfFirstSlash == 0) {
// Not a relative path ...
throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
}
@@ -784,7 +750,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (relativePath.equals(".")) return this;
if (relativePath.equals("..")) return this.getParent();
int indexOfFirstSlash = relativePath.indexOf('/');
- if (indexOfFirstSlash == 0 || relativePath.startsWith("[")) {
+ if (indexOfFirstSlash == 0) {
// Not a relative path ...
throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
}
@@ -798,13 +764,17 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
}
// We know it's a resolved relative path with more than one segment ...
if (path.size() > 1) {
- return cache.findJcrNode(nodeId, location.getPath(), path);
+ AbstractJcrItem item = cache.findJcrNode(nodeId, location.getPath(), path);
+ if (item instanceof javax.jcr.Node) {
+ return (AbstractJcrNode)item;
+ }
+ I18n msg = JcrI18n.nodeNotFoundAtPathRelativeToReferenceNode;
+ throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
}
segment = path.getLastSegment();
} else {
segment = segmentFrom(relativePath);
}
- assert !segment.isIdentifier();
// It's just a name, so look for a child ...
try {
return nodeInfo().getChild(segment).getPayload().getJcrNode();
@@ -1265,9 +1235,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (path.size() == 0) {
throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
}
- if (path.isIdentifier()) {
- throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
- }
if (path.getLastSegment().getIndex() > 1 || relPath.endsWith("]")) {
throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
}
@@ -1363,9 +1330,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (path.size() == 0) {
return false;
}
- if (path.isIdentifier()) {
- return false;
- }
if (path.getLastSegment().getIndex() > 1 || relPath.endsWith("]")) {
return false;
}
@@ -1966,10 +1930,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
PathFactory pathFactory = this.cache.pathFactory();
Path srcPath = pathFactory.create(srcChildRelPath);
- if (srcPath.isAbsolute()) {
- // Not a relative path ...
- throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(srcChildRelPath, "relativePath"));
- }
if (srcPath.isAbsolute() || srcPath.size() != 1) {
throw new ItemNotFoundException(JcrI18n.pathNotFound.text(srcPath.getString(cache.context().getNamespaceRegistry()),
cache.session().workspace().getName()));
@@ -1987,13 +1947,9 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (destChildRelPath != null) {
Path destPath = pathFactory.create(destChildRelPath);
- if (destPath.isAbsolute()) {
- // Not a relative path ...
- throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(destChildRelPath, "relativePath"));
- }
- if (destPath.size() != 1) {
- throw new ItemNotFoundException(JcrI18n.pathNotFound.text(destPath.getString(cache.context()
- .getNamespaceRegistry()),
+ if (destPath.isAbsolute() || destPath.size() != 1) {
+ throw new ItemNotFoundException(
+ JcrI18n.pathNotFound.text(destPath.getString(cache.context().getNamespaceRegistry()),
cache.session().workspace().getName()));
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (revision 1859)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (working copy)
@@ -89,8 +89,6 @@ public final class JcrI18n {
public static I18n itemAlreadyExistsWithUuid;
public static I18n itemNotFoundAtPath;
public static I18n itemNotFoundAtPathRelativeToReferenceNode;
- public static I18n identifierPathContainedUnsupportedIdentifierFormat;
- public static I18n identifierPathNeverReferencesProperty;
public static I18n propertyNotFoundOnNode;
public static I18n propertyNotFoundAtPathRelativeToReferenceNode;
public static I18n nodeNotFoundAtPathRelativeToReferenceNode;
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepositoryFactory.java
new file mode 100644
===================================================================
--- /dev/null (revision 1859)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepositoryFactory.java (working copy)
@@ -0,0 +1,306 @@
+package org.modeshape.jcr;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import net.jcip.annotations.ThreadSafe;
+import org.modeshape.common.collection.Problem;
+import org.modeshape.common.util.Logger;
+import org.modeshape.jcr.api.RepositoryFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * Service provider for the JCR2 {@code RepositoryFactory} interface. This class provides a single public method,
+ * {@link #getRepository(Map)}, that allows for a runtime link to a ModeShape JCR repository.
+ *
+ * The canonical way to get a reference to this class is to use the ServiceLocator:
+ *
+ *
+ *
+ * It is also possible to instantiate this class directly.
+ *
+ *
+ * RepositoryFactory repoFactory = new JcrRepositoryFactory();
+ * String configUrl = ... ; // URL that points to your configuration file
+ * Map params = Collections.singletonMap(JcrRepositoryFactory.URL, configUrl);
+ *
+ * Repository repository = repoFactory.getRepository(params);]]>
+ *
+ *
+ *
+ *
+ * The configUrl used in the sample above should point to a configuration file (e.g., {@code
+ * file:src/test/resources/configRepository.xml?repositoryName=MyRepository}) OR a {@link JcrEngine} stored in the JNDI tree
+ * (e.g., {@code jndi://name/of/JcrEngine/resource?repositoryName=MyRepository}).
+ *
+ *
+ * @see #getRepository(Map)
+ * @see RepositoryFactory#getRepository(Map)
+ */
+@ThreadSafe
+public class JcrRepositoryFactory implements RepositoryFactory {
+
+ private static final Logger LOG = Logger.getLogger(JcrRepositoryFactory.class);
+
+ /**
+ * A map of configuration file locations to existing engines. This map helps ensure that JcrEngines are not recreated with
+ * every call to {@link #getRepository(Map)}.
+ */
+ private static final Map ENGINES = new HashMap();
+
+ /** The name of the key for the ModeShape JCR URL in the parameter map */
+ public static final String URL = "org.modeshape.jcr.URL";
+
+ /** The name of the URL parameter that specifies the repository name. */
+ public static final String REPOSITORY_NAME_PARAM = "repositoryName";
+
+ /**
+ * Returns a reference to the appropriate repository for the given parameter map, if one exists. Although the {@code
+ * parameters} map can have any number of entries, this method only considers the entry with the key JcrRepositoryFactory#URL.
+ *
+ * The value of this key is treated as a URL with the format {@code PROTOCOL://PATH[?repositoryName=REPOSITORY_NAME]} where
+ * PROTOCOL is "jndi" or "file", PATH is the JNDI name of the JcrEngine or the path to the configuration file, and
+ * REPOSITORY_NAME is the name of the repository to return if there is more than one JCR repository in the given JcrEngine or
+ * configuration file.
+ *
+ *
+ * @param parameters a map of parameters to use to look up the repository; may be null
+ * @return the repository specified by the value of the entry with key {@link #URL}, or null if any of the following are true:
+ *
+ *
the parameters map is empty; or,
+ *
there is no parameter with the {@link #URL}; or,
+ *
the value for the {@link #URL} key is null or cannot be parsed into a ModeShape JCR URL; or,
+ *
the ModeShape JCR URL is parseable but does not point to a JcrEngine (in the JNDI tree) or a configuration file
+ * (in the classpath or file system); or,
+ *
or there is an error starting up the JcrEngine with the given configuration information.
+ *
+ * @see RepositoryFactory#getRepository(Map)
+ */
+ @Override
+ public Repository getRepository( Map parameters ) {
+ LOG.debug("Trying to load ModeShape JCR Repository with parameters: " + parameters);
+ if (parameters == null) return null;
+
+ String rawUrl = parameters.get(URL);
+ if (rawUrl == null) {
+ LOG.debug("No parameter found with key: " + URL);
+ return null;
+ }
+
+ URL url;
+ try {
+ url = new URL(rawUrl);
+ } catch (MalformedURLException mue) {
+ LOG.debug("Could not parse URL: " + mue.getMessage());
+ return null;
+ }
+
+ if (url.getPath() == null || url.getPath().trim().length() == 0) {
+ LOG.debug("Cannot have null or empty path in repository URL");
+ return null;
+ }
+
+ JcrEngine engine = null;
+
+ if ("jndi".equals(url.getProtocol())) {
+ engine = getEngineFromJndi(url.getPath(), parameters);
+ } else {
+ engine = getEngineFromConfigFile(url);
+ }
+
+ if (engine == null) {
+ LOG.debug("Could not load engine from URL: " + url);
+ return null;
+ }
+
+ String query = url.getQuery();
+ String repositoryName = null;
+ if (query != null) {
+ for (String keyValuePair : query.split("&")) {
+ String[] splitPair = keyValuePair.split("=");
+
+ if (splitPair.length == 2 && REPOSITORY_NAME_PARAM.equals(splitPair[0])) {
+ repositoryName = splitPair[1];
+ break;
+ }
+ }
+ }
+
+ if (repositoryName == null) {
+ Set repositoryNames = engine.getRepositoryNames();
+
+ if (repositoryNames.size() != 1) {
+ LOG.debug("No repository name provided in URL and multiple repositories configured in engine with following names: "
+ + repositoryNames);
+ return null;
+ }
+
+ repositoryName = repositoryNames.iterator().next();
+ }
+
+ try {
+ LOG.debug("Trying to access repository: " + repositoryName);
+ return engine.getRepository(repositoryName);
+ } catch (RepositoryException re) {
+ LOG.debug(re, "Could not load repository named '{0}'", repositoryName);
+ return null;
+ }
+ }
+
+ /**
+ * Returns a {@link JcrEngine} for the configuration in the given file.
+ *
+ * If a {@link JcrEngine} has already been loaded by this class for the given configuration file, that engine will be reused.
+ *
+ *
+ * @param configUrl the URL to the file in the file system or relative to the classpath; may not be null
+ * @return a {@code JcrEngine} that was initialized from the given configuration file or null if no engine could be
+ * initialized from that file without errors.
+ */
+ private JcrEngine getEngineFromConfigFile( URL configUrl ) {
+ assert configUrl != null;
+
+ synchronized (ENGINES) {
+ String configKey = configUrl.toString();
+
+ JcrEngine engine = ENGINES.get(configKey);
+ if (engine != null) return engine;
+
+ JcrConfiguration config = new JcrConfiguration();
+ try {
+ config.loadFrom(configUrl);
+ } catch (FileNotFoundException fnfe) {
+ // If this is a file protocol, double-check that the configuration isn't on the classpath
+ if (!"file".equals(configUrl.getProtocol())) {
+ LOG.warn(fnfe, JcrI18n.couldNotStartEngine);
+ return null;
+
+ }
+ try {
+ InputStream in = getClass().getResourceAsStream(configUrl.getPath());
+ if (in == null) {
+ LOG.debug(fnfe, JcrI18n.couldNotStartEngine.text());
+ return null;
+ }
+ config.loadFrom(in);
+ } catch (IOException ioe) {
+ LOG.debug(fnfe, JcrI18n.couldNotStartEngine.text());
+ return null;
+ } catch (SAXException se) {
+ LOG.debug(fnfe, JcrI18n.couldNotStartEngine.text());
+ return null;
+ }
+ } catch (IOException ioe) {
+ LOG.warn(ioe, JcrI18n.couldNotStartEngine);
+ return null;
+ } catch (SAXException se) {
+ LOG.warn(se, JcrI18n.couldNotStartEngine);
+ return null;
+ }
+ engine = config.build();
+ engine.start();
+
+ if (engine.getProblems().hasProblems()) {
+ LOG.warn(JcrI18n.couldNotStartEngine);
+ for (Problem problem : engine.getProblems()) {
+ LOG.warn(problem.getMessage(), problem.getParameters());
+ }
+
+ engine.shutdown();
+ return null;
+ }
+
+ ENGINES.put(configKey, engine);
+ return engine;
+ }
+ }
+
+ /**
+ * Returns a hashtable with the same key/value mappings as the given map
+ *
+ * @param map the set of key/value mappings to convert; may not be null
+ * @return a hashtable with the same key/value mappings as the given map; may be empty, never null
+ */
+ private Hashtable hashtable( Map map ) {
+ assert map != null;
+
+ Hashtable hash = new Hashtable(map.size());
+
+ for (Map.Entry entry : map.entrySet()) {
+ hash.put(entry.getKey(), entry.getValue());
+ }
+
+ return hash;
+ }
+
+ /**
+ * Attempts to look up a JcrEngine at the given JNDI name. All parameters in the parameters map are passed to the
+ * {@link InitialContext} constructor in a {@link Hashtable}.
+ *
+ * @param engineJndiName the JNDI name of the JCR engine; may not be null
+ * @param parameters any additional parameters that should be passed to the {@code InitialContext}'s constructor; may be empty
+ * but may not be null
+ * @return the JcrEngine from JNDI, if one exists at the given name
+ */
+ private JcrEngine getEngineFromJndi( String engineJndiName,
+ Map parameters ) {
+ try {
+ InitialContext ic = new InitialContext(hashtable(parameters));
+
+ Object ob = ic.lookup(engineJndiName);
+ if (!(ob instanceof JcrEngine)) return null;
+ return (JcrEngine)ob;
+ } catch (NamingException ne) {
+ return null;
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ synchronized (ENGINES) {
+ for (JcrEngine engine : ENGINES.values()) {
+ engine.shutdown();
+ }
+
+ ENGINES.clear();
+ }
+ }
+
+ @Override
+ public boolean shutdown( long timeout,
+ TimeUnit unit ) throws InterruptedException {
+ synchronized (ENGINES) {
+ for (JcrEngine engine : ENGINES.values()) {
+ engine.shutdown();
+ }
+
+ boolean allShutDownClean = true;
+ for (JcrEngine engine : ENGINES.values()) {
+ allShutDownClean &= engine.awaitTermination(timeout, unit);
+ }
+
+ ENGINES.clear();
+ return allShutDownClean;
+ }
+ }
+}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java (revision 1859)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java (working copy)
@@ -177,9 +177,7 @@ class JcrSession implements Session {
this.cache = new SessionCache(this);
this.isLive = true;
- this.performReferentialIntegrityChecks = Boolean.valueOf(repository.getOptions()
- .get(Option.PERFORM_REFERENTIAL_INTEGRITY_CHECKS))
- .booleanValue();
+ this.performReferentialIntegrityChecks = Boolean.valueOf(repository.getOptions().get(Option.PERFORM_REFERENTIAL_INTEGRITY_CHECKS)).booleanValue();
assert this.sessionAttributes != null;
assert this.workspace != null;
@@ -423,6 +421,7 @@ class JcrSession implements Session {
String pathAsString = path != null ? path.getString(this.namespaces()) : "";
throw new AccessControlException(JcrI18n.permissionDenied.text(pathAsString, actions));
+
}
/**
@@ -462,6 +461,7 @@ class JcrSession implements Session {
hasPermission &= hasRole(ModeShapeRoles.ADMIN, workspaceName) || hasRole(ModeShapeRoles.READWRITE, workspaceName);
}
}
+
return hasPermission;
}
@@ -496,9 +496,11 @@ class JcrSession implements Session {
CheckArg.isInstanceOf(arguments[1], String.class, "arguments[1]");
primaryNodeTypeName = (String)arguments[1];
}
+
return node.canAddNode(relPath, primaryNodeTypeName);
}
}
+
return true;
}
@@ -513,9 +515,12 @@ class JcrSession implements Session {
boolean noRecurse ) throws RepositoryException, SAXException {
CheckArg.isNotNull(absPath, "absPath");
CheckArg.isNotNull(contentHandler, "contentHandler");
+
Path exportRootPath = executionContext.getValueFactories().getPathFactory().create(absPath);
Node exportRootNode = getNode(exportRootPath);
+
AbstractJcrExporter exporter = new JcrDocumentViewExporter(this);
+
exporter.exportView(exportRootNode, contentHandler, skipBinary, noRecurse);
}
@@ -530,9 +535,12 @@ class JcrSession implements Session {
boolean noRecurse ) throws RepositoryException {
CheckArg.isNotNull(absPath, "absPath");
CheckArg.isNotNull(out, "out");
+
Path exportRootPath = executionContext.getValueFactories().getPathFactory().create(absPath);
Node exportRootNode = getNode(exportRootPath);
+
AbstractJcrExporter exporter = new JcrDocumentViewExporter(this);
+
exporter.exportView(exportRootNode, out, skipBinary, noRecurse);
}
@@ -547,9 +555,12 @@ class JcrSession implements Session {
boolean noRecurse ) throws RepositoryException, SAXException {
CheckArg.isNotNull(absPath, "absPath");
CheckArg.isNotNull(contentHandler, "contentHandler");
+
Path exportRootPath = executionContext.getValueFactories().getPathFactory().create(absPath);
Node exportRootNode = getNode(exportRootPath);
+
AbstractJcrExporter exporter = new JcrSystemViewExporter(this);
+
exporter.exportView(exportRootNode, contentHandler, skipBinary, noRecurse);
}
@@ -564,9 +575,12 @@ class JcrSession implements Session {
boolean noRecurse ) throws RepositoryException {
CheckArg.isNotNull(absPath, "absPath");
CheckArg.isNotNull(out, "out");
+
Path exportRootPath = executionContext.getValueFactories().getPathFactory().create(absPath);
Node exportRootNode = getNode(exportRootPath);
+
AbstractJcrExporter exporter = new JcrSystemViewExporter(this);
+
exporter.exportView(exportRootNode, out, skipBinary, noRecurse);
}
@@ -578,6 +592,7 @@ class JcrSession implements Session {
public ContentHandler getImportContentHandler( String parentAbsPath,
int uuidBehavior ) throws PathNotFoundException, RepositoryException {
Path parentPath = this.executionContext.getValueFactories().getPathFactory().create(parentAbsPath);
+
return new JcrContentHandler(this, parentPath, uuidBehavior, SaveMode.SESSION);
}
@@ -595,7 +610,7 @@ class JcrSession implements Session {
return getRootNode();
}
// Since we don't know whether path refers to a node or a property, look to see if we can tell it's a node ...
- if (path.isIdentifier() || path.getLastSegment().hasIndex()) {
+ if (path.getLastSegment().hasIndex()) {
return getNode(path);
}
// We can't tell from the name, so ask for an item ...
@@ -640,6 +655,7 @@ class JcrSession implements Session {
if (path.isRoot()) {
return true;
}
+
try {
cache.findJcrNode(null, path);
return true;
@@ -663,9 +679,6 @@ class JcrSession implements Session {
if (path.isRoot()) {
throw new PathNotFoundException(JcrI18n.rootNodeIsNotProperty.text());
}
- if (path.isIdentifier()) {
- throw new PathNotFoundException(JcrI18n.identifierPathNeverReferencesProperty.text());
- }
Segment lastSegment = path.getLastSegment();
if (lastSegment.hasIndex()) {
@@ -695,7 +708,7 @@ class JcrSession implements Session {
CheckArg.isNotEmpty(absolutePath, "absolutePath");
// Return root node if path is "/"
Path path = executionContext.getValueFactories().getPathFactory().create(absolutePath);
- if (path.isRoot() || path.isIdentifier()) {
+ if (path.isRoot()) {
return false;
}
@@ -715,6 +728,7 @@ class JcrSession implements Session {
public void removeItem( String absolutePath ) throws RepositoryException {
Item item = getItem(absolutePath);
+
item.remove();
}
@@ -738,17 +752,6 @@ class JcrSession implements Session {
AbstractJcrNode getNode( Path path ) throws RepositoryException, PathNotFoundException {
if (path.isRoot()) return cache.findJcrRootNode();
try {
- if (path.isIdentifier()) {
- // Convert the path to a UUID ...
- try {
- UUID uuid = executionContext.getValueFactories().getUuidFactory().create(path);
- return cache.findJcrNode(Location.create(uuid));
- } catch (org.modeshape.graph.property.ValueFormatException e) {
- // The identifier path didn't contain a UUID (but another identifier form) ...
- String pathStr = executionContext.getValueFactories().getStringFactory().create(path);
- throw new PathNotFoundException(JcrI18n.identifierPathContainedUnsupportedIdentifierFormat.text(pathStr));
- }
- }
return cache.findJcrNode(null, path);
} catch (ItemNotFoundException e) {
throw new PathNotFoundException(e.getMessage());
@@ -761,7 +764,9 @@ class JcrSession implements Session {
* @see javax.jcr.Session#getNodeByUUID(java.lang.String)
*/
public AbstractJcrNode getNodeByUUID( String uuid ) throws ItemNotFoundException, RepositoryException {
- return cache.findJcrNode(Location.create(UUID.fromString(uuid)));
+ AbstractJcrNode node = cache.findJcrNode(Location.create(UUID.fromString(uuid)));
+
+ return node;
}
/**
@@ -1014,22 +1019,14 @@ class JcrSession implements Session {
PathFactory pathFactory = executionContext.getValueFactories().getPathFactory();
Path destPath = pathFactory.create(destAbsPath);
+ Path.Segment newNodeName = destPath.getSegment(destPath.size() - 1);
// Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node"
if (destAbsPath.endsWith("]")) {
throw new RepositoryException(JcrI18n.pathCannotHaveSameNameSiblingIndex.text(destAbsPath));
}
- Path.Segment newNodeName = null;
AbstractJcrNode sourceNode = getNode(pathFactory.create(srcAbsPath));
- AbstractJcrNode newParentNode = null;
- if (destPath.isIdentifier()) {
- AbstractJcrNode existingDestNode = getNode(destPath);
- newParentNode = existingDestNode.getParent();
- newNodeName = existingDestNode.segment();
- } else {
- newParentNode = getNode(destPath.getParent());
- newNodeName = destPath.getSegment(destPath.size() - 1);
- }
+ AbstractJcrNode newParentNode = getNode(destPath.getParent());
if (sourceNode.isLocked() && !sourceNode.getLock().isLockOwningSession()) {
javax.jcr.lock.Lock sourceLock = sourceNode.getLock();
@@ -1098,13 +1095,8 @@ class JcrSession implements Session {
TypeSystem typeSystem = executionContext.getValueFactories().getTypeSystem();
QueryBuilder builder = new QueryBuilder(typeSystem);
- QueryCommand query = builder.select("jcr:uuid")
- .from("mix:referenceable AS referenceable")
- .where()
- .path("referenceable")
- .isLike(pathStr + "%")
- .end()
- .query();
+ QueryCommand query = builder.select("jcr:uuid").from("mix:referenceable AS referenceable").where().path("referenceable").isLike(pathStr
+ + "%").end().query();
JcrQueryManager queryManager = workspace().queryManager();
Query jcrQuery = queryManager.createQuery(query);
QueryResult result = jcrQuery.execute();
@@ -1197,24 +1189,10 @@ class JcrSession implements Session {
QueryBuilder builder = new QueryBuilder(typeSystem);
QueryCommand query = null;
if (subgraphPath != null) {
- query = builder.select("jcr:primaryType")
- .fromAllNodesAs("allNodes")
- .where()
- .referenceValue("allNodes")
- .isIn(someUuidsInBranch)
- .and()
- .path("allNodes")
- .isLike(subgraphPath + "%")
- .end()
- .query();
+ query = builder.select("jcr:primaryType").fromAllNodesAs("allNodes").where().referenceValue("allNodes").isIn(someUuidsInBranch).and().path("allNodes").isLike(subgraphPath
+ + "%").end().query();
} else {
- query = builder.select("jcr:primaryType")
- .fromAllNodesAs("allNodes")
- .where()
- .referenceValue("allNodes")
- .isIn(someUuidsInBranch)
- .end()
- .query();
+ query = builder.select("jcr:primaryType").fromAllNodesAs("allNodes").where().referenceValue("allNodes").isIn(someUuidsInBranch).end().query();
}
Query jcrQuery = workspace().queryManager().createQuery(query);
// The nodes that have been (transiently) deleted will not appear in these results ...
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrWorkspace.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrWorkspace.java (revision 1859)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrWorkspace.java (working copy)
@@ -338,25 +338,15 @@ class JcrWorkspace implements Workspace {
}
// Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node"
- if (!destPath.isIdentifier() && destAbsPath.endsWith("]")) {
+ if (destAbsPath.endsWith("]")) {
throw new RepositoryException(JcrI18n.pathCannotHaveSameNameSiblingIndex.text(destAbsPath));
}
try {
// Use the session to verify that the node location has a definition and is valid with the new cloned child.
// This also performs the check permission for reading the parent ...
+ Name newNodeName = destPath.getLastSegment().getName();
SessionCache cache = this.session.cache();
- AbstractJcrNode parentNode = null;
- Name newNodeName = null;
- if (destPath.isIdentifier()) {
- AbstractJcrNode existingDestNode = cache.findJcrNode(Location.create(destPath));
- parentNode = existingDestNode.getParent();
- newNodeName = existingDestNode.name();
- destPath = factory.create(parentNode.path(), newNodeName);
- } else {
- parentNode = cache.findJcrNode(null, destPath.getParent());
- newNodeName = destPath.getLastSegment().getName();
- }
/*
* Find the UUID for the source node. Have to go directly against the graph.
@@ -373,6 +363,8 @@ class JcrWorkspace implements Workspace {
}
}
+ AbstractJcrNode parentNode = cache.findJcrNode(Location.create(destPath.getParent()));
+
if (parentNode.isLocked()) {
Lock newParentLock = parentNode.getLock();
if (newParentLock != null && newParentLock.getLockToken() == null) {
@@ -384,7 +376,7 @@ class JcrWorkspace implements Workspace {
throw new VersionException(JcrI18n.nodeIsCheckedIn.text(parentNode.getPath()));
}
- Node parent = cache.findNode(parentNode.nodeId, parentNode.path());
+ Node parent = cache.findNode(null, destPath.getParent());
cache.findBestNodeDefinition(parent, newNodeName, parent.getPayload().getPrimaryTypeName());
if (removeExisting) {
@@ -448,8 +440,7 @@ class JcrWorkspace implements Workspace {
String existingWorkspace = graph.getCurrentWorkspaceName();
try {
graph.useWorkspace(workspace);
- Location location = Location.create(sourcePath);
- Subgraph subgraph = graph.getSubgraphOfDepth(ReadBranchRequest.NO_MAXIMUM_DEPTH).at(location);
+ Subgraph subgraph = graph.getSubgraphOfDepth(ReadBranchRequest.NO_MAXIMUM_DEPTH).at(sourcePath);
// Collect up the UUIDs; we use UUID here because that's what JCR requires ...
Set uuids = new HashSet();
for (SubgraphNode nodeInSubgraph : subgraph) {
@@ -507,25 +498,15 @@ class JcrWorkspace implements Workspace {
}
// Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node"
- if (!destPath.isIdentifier() && destAbsPath.endsWith("]")) {
+ if (destAbsPath.endsWith("]")) {
throw new RepositoryException(JcrI18n.pathCannotHaveSameNameSiblingIndex.text(destAbsPath));
}
try {
// Use the session to verify that the node location has a definition and is valid with the new cloned child.
// This also performs the check permission for reading the parent ...
+ Name newNodeName = destPath.getLastSegment().getName();
SessionCache cache = this.session.cache();
- AbstractJcrNode parentNode = null;
- Name newNodeName = null;
- if (destPath.isIdentifier()) {
- AbstractJcrNode existingDestNode = cache.findJcrNode(Location.create(destPath));
- parentNode = existingDestNode.getParent();
- newNodeName = existingDestNode.name();
- destPath = factory.create(parentNode.path(), newNodeName);
- } else {
- parentNode = cache.findJcrNode(null, destPath.getParent());
- newNodeName = destPath.getLastSegment().getName();
- }
/*
* Find the UUID for the source node. Have to go directly against the graph.
@@ -548,6 +529,8 @@ class JcrWorkspace implements Workspace {
Property primaryTypeProp = sourceNode.getProperty(JcrLexicon.PRIMARY_TYPE);
Name primaryTypeName = this.context.getValueFactories().getNameFactory().create(primaryTypeProp.getFirstValue());
+ AbstractJcrNode parentNode = cache.findJcrNode(Location.create(destPath.getParent()));
+
if (parentNode.isLocked()) {
Lock newParentLock = parentNode.getLock();
if (newParentLock != null && newParentLock.getLockToken() == null) {
@@ -606,7 +589,9 @@ class JcrWorkspace implements Workspace {
CheckArg.isNotNull(parentAbsPath, "parentAbsPath");
session.checkLive();
+
Path parentPath = this.context.getValueFactories().getPathFactory().create(parentAbsPath);
+
return new JcrContentHandler(this.session, parentPath, uuidBehavior, SaveMode.WORKSPACE);
}
@@ -672,26 +657,16 @@ class JcrWorkspace implements Workspace {
}
// Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node"
- if (!destPath.isIdentifier() && destAbsPath.endsWith("]")) {
+ if (destAbsPath.endsWith("]")) {
throw new RepositoryException(JcrI18n.pathCannotHaveSameNameSiblingIndex.text(destAbsPath));
}
try {
// Use the session to verify that the node location has a definition and is valid with the new cloned child.
// This also performs the check permission for reading the parent ...
+ Name newNodeName = destPath.getLastSegment().getName();
SessionCache cache = this.session.cache();
- Node newParent = null;
- Name newNodeName = null;
- if (destPath.isIdentifier()) {
- Node existingDestNode = cache.findNodeWith(Location.create(destPath));
- newParent = existingDestNode.getParent();
- newNodeName = existingDestNode.getName();
- destPath = factory.create(newParent.getPath(), newNodeName);
- } else {
- newParent = cache.findNode(null, destPath.getParent());
- newNodeName = destPath.getLastSegment().getName();
- }
-
+ Node newParent = cache.findNode(null, destPath.getParent());
cache.findBestNodeDefinition(newParent, newNodeName, newParent.getPayload().getPrimaryTypeName());
AbstractJcrNode sourceNode = cache.findJcrNode(Location.create(srcPath));
@@ -703,7 +678,7 @@ class JcrWorkspace implements Workspace {
}
}
- AbstractJcrNode parentNode = cache.findJcrNode(newParent.getNodeId(), newParent.getPath());
+ AbstractJcrNode parentNode = cache.findJcrNode(Location.create(destPath.getParent()));
if (parentNode.isLocked()) {
Lock newParentLock = parentNode.getLock();
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/SessionCache.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/SessionCache.java (revision 1859)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/SessionCache.java (working copy)
@@ -464,29 +464,6 @@ class SessionCache {
}
/**
- * Find the session's node for the given location.
- *
- * @param location the location for the node
- * @return the existing node implementation
- * @throws IllegalArgumentException if the identifier and path are both node
- * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
- * @throws AccessDeniedException if the caller does not have privilege to read the node
- * @throws RepositoryException if an error resulting in finding this node in the repository
- */
- public Node findNodeWith( Location location )
- throws ItemNotFoundException, AccessDeniedException, RepositoryException {
- try {
- return graphSession.findNodeWith(location);
- } catch (org.modeshape.graph.property.PathNotFoundException e) {
- throw new ItemNotFoundException(e.getMessage(), e);
- } catch (RepositorySourceException e) {
- throw new RepositoryException(e.getMessage(), e);
- } catch (AccessControlException e) {
- throw new AccessDeniedException(e.getMessage(), e);
- }
- }
-
- /**
* Find the session's node for the given identifier and path.
*
* @param from the identifier of the reference node; may be null if the root node is to be used as the reference
Index: modeshape-jcr/src/main/resources/META-INF/services/javax.jcr.RepositoryFactory
new file mode 100644
===================================================================
--- /dev/null (revision 1859)
+++ modeshape-jcr/src/main/resources/META-INF/services/javax.jcr.RepositoryFactory (working copy)
@@ -0,0 +1 @@
+org.modeshape.jcr.JcrRepositoryFactory # ModeShape JCR Implementation
\ No newline at end of file
Index: modeshape-jcr/src/main/resources/META-INF/services/org.modeshape.jcr.api.RepositoryFactory
new file mode 100644
===================================================================
--- /dev/null (revision 1859)
+++ modeshape-jcr/src/main/resources/META-INF/services/org.modeshape.jcr.api.RepositoryFactory (working copy)
@@ -0,0 +1 @@
+org.modeshape.jcr.JcrRepositoryFactory
Index: modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties
===================================================================
--- modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (revision 1859)
+++ modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (working copy)
@@ -79,8 +79,6 @@ itemNotFoundWithUuid = An item with UUID "{0}" could not be found in workspace "
itemAlreadyExistsWithUuid = An item with UUID "{0}" already exists in workspace "{1}" at "{2}"
itemNotFoundAtPath = An item at "{0}" could not be found in workspace "{1}"
itemNotFoundAtPathRelativeToReferenceNode = An item at "{0}" relative to "{1}" could not be found in workspace "{2}"
-identifierPathContainedUnsupportedIdentifierFormat = The identifier path "{0}" does not contain a known identifier format
-identifierPathNeverReferencesProperty = Identifier paths such as "{0}" only point to nodes, and never to properties
propertyNotFoundOnNode = Property "{0}" does not exist on node "{1}" in workspace "{2}"
propertyNotFoundAtPathRelativeToReferenceNode = A property at "{0}" relative to "{1}" could not be found in workspace "{2}"
nodeNotFoundAtPathRelativeToReferenceNode = A node at "{0}" relative to "{1}" could not be found in workspace "{2}"
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrNodeTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrNodeTest.java (revision 1859)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrNodeTest.java (working copy)
@@ -33,7 +33,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
-import java.util.UUID;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
@@ -63,8 +62,6 @@ import org.modeshape.jcr.nodetype.PropertyDefinitionTemplate;
*/
public class AbstractJcrNodeTest extends AbstractJcrTest {
- private static final String ID_PATH = "[" + UUID.randomUUID() + "]";
-
private AbstractJcrNode rootNode;
private AbstractJcrNode cars;
private AbstractJcrNode hybrid;
@@ -169,11 +166,6 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
prius.getProperty("../bogus/path");
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldFailToReturnPropertyFromGetPropertyWithIdentifierPath() throws Exception {
- prius.getProperty(ID_PATH);
- }
-
@Test
public void shouldReturnPropertyFromGetPropertyWithRelativePathToPropertyOnOtherNode() throws Exception {
javax.jcr.Property property = prius.getProperty("../Nissan Altima/vehix:model");
@@ -228,16 +220,6 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasNodeWithIdentifierPath() throws Exception {
- prius.hasNode(ID_PATH);
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasNodeWithAbsolutePath() throws Exception {
- prius.hasNode("/something");
- }
-
- @Test( expected = IllegalArgumentException.class )
public void shouldNotAllowHasPropertyWithAbsolutePath() throws Exception {
prius.hasProperty("/Cars/Hybrid/Toyota Prius/vehix:model");
}
@@ -252,11 +234,6 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
prius.hasProperty("");
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasPropertyWithIdentifierPath() throws Exception {
- prius.hasProperty(ID_PATH);
- }
-
@Test
public void shouldReturnFalseFromHasPropertyIfPathIsParentPath() throws Exception {
assertThat(prius.hasProperty(".."), is(false));
@@ -332,16 +309,6 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
prius.getNode((String)null);
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetNodeWithIdentifierPath() throws Exception {
- prius.getNode(ID_PATH);
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetNodeWithAbsolutePath() throws Exception {
- prius.getNode("/something");
- }
-
@Test
public void shouldProvideNodeIterator() throws Exception {
NodeIterator iter = hybrid.getNodes();
@@ -586,16 +553,6 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
hybrid.orderBefore(null, null);
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowOrderBeforeWithIdentifierPathAsFirstParameter() throws Exception {
- hybrid.orderBefore(ID_PATH, "/something");
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowOrderBeforeWithIdentifierPathAsSecondParameter() throws Exception {
- hybrid.orderBefore("/something", ID_PATH);
- }
-
/*
* Primary-type and -item methods
*/
@@ -707,7 +664,7 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository2, "workspace2", null);
JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
+
// Use the same id and location; use 'Toyota Prius'
// since the UUID is defined in 'cars.xml' and therefore will be the same
javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java (revision 1859)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java (working copy)
@@ -23,8 +23,6 @@
*/
package org.modeshape.jcr;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
@@ -201,13 +199,4 @@ public abstract class AbstractSessionTest {
options.put(JcrRepository.Option.PROJECT_NODE_TYPES, Boolean.FALSE.toString());
}
-
- protected String identifierPathFor( String pathToNode ) throws Exception {
- AbstractJcrNode node = session.getNode(pathToNode);
- if (node.isNodeType("mix:referenceable")) {
- // Make sure that the identifier matches the UUID ...
- assertThat(node.getUUID(), is(node.identifier()));
- }
- return node.identifierPath();
- }
}
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrRepositoryFactoryTest.java
new file mode 100644
===================================================================
--- /dev/null (revision 1859)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrRepositoryFactoryTest.java (working copy)
@@ -0,0 +1,80 @@
+package org.modeshape.jcr;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import java.util.Collections;
+import java.util.Map;
+import java.util.ServiceLoader;
+import javax.jcr.Repository;
+import org.junit.Test;
+import org.modeshape.jcr.api.RepositoryFactory;
+
+public class JcrRepositoryFactoryTest {
+
+ private String url;
+ private Map params;
+ private Repository repository;
+
+ @Test
+ public void shouldReturnRepositoryFromConfigurationFile() {
+ url = "file:src/test/resources/tck/default/configRepository.xml?repositoryName=Test Repository Source";
+ params = Collections.singletonMap(JcrRepositoryFactory.URL, url);
+
+ repository = repositoryFor(params);
+ assertThat(repository, is(notNullValue()));
+ }
+
+ @Test
+ public void shouldReturnRepositoryFromConfigurationClasspathResource() {
+ url = "file:///tck/default/configRepository.xml?repositoryName=Test Repository Source";
+ params = Collections.singletonMap(JcrRepositoryFactory.URL, url);
+
+ repository = repositoryFor(params);
+ assertThat(repository, is(notNullValue()));
+ }
+
+ @Test
+ public void shouldReturnSameRepositoryFromSameConfigurationFile() {
+ url = "file:src/test/resources/tck/default/configRepository.xml?repositoryName=Test Repository Source";
+ params = Collections.singletonMap(JcrRepositoryFactory.URL, url);
+
+ repository = repositoryFor(params);
+ assertThat(repository, is(notNullValue()));
+
+ Repository repository2 = repositoryFor(params);
+ assertThat(repository2, is(notNullValue()));
+ assertThat(repository, is(repository2));
+
+ }
+
+ @Test
+ public void shouldNotReturnRepositoryForInvalidUrl() {
+ url = "file:?Test Repository Source";
+ assertThat(repositoryFor(Collections.singletonMap(JcrRepositoryFactory.URL, url)), is(nullValue()));
+
+ url = "file:src/test/resources/tck/default/nonExistentFile";
+ assertThat(repositoryFor(Collections.singletonMap(JcrRepositoryFactory.URL, url)), is(nullValue()));
+ }
+
+ @Test
+ public void shouldReturnRepositoryWithoutNameIfOnlyOneRepositoryInEngine() {
+ url = "file:src/test/resources/tck/default/configRepository.xml";
+ params = Collections.singletonMap(JcrRepositoryFactory.URL, url);
+
+ repository = repositoryFor(params);
+ assertThat(repository, is(notNullValue()));
+
+ }
+
+ protected Repository repositoryFor( Map parameters ) {
+ Repository repository;
+ for (RepositoryFactory factory : ServiceLoader.load(RepositoryFactory.class)) {
+ repository = factory.getRepository(parameters);
+ if (repository != null) return repository;
+ }
+
+ return null;
+ }
+}
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrSessionTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrSessionTest.java (revision 1859)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrSessionTest.java (working copy)
@@ -234,49 +234,6 @@ public class JcrSessionTest extends AbstractSessionTest {
}
@Test
- public void shouldGetItemByIdentifierPath() throws Exception {
- // Look up the node by the identifier path ...
- Item item = session.getItem(identifierPathFor("/a"));
- assertThat(item, instanceOf(Node.class));
- assertThat(item.getPath(), is("/a"));
-
- item = session.getItem(identifierPathFor("/a/b"));
- assertThat(item, instanceOf(Node.class));
- assertThat(item.getPath(), is("/a/b"));
-
- item = session.getItem(identifierPathFor("/"));
- assertThat(item, instanceOf(Node.class));
- assertThat(item.getPath(), is("/"));
- }
-
- @Test
- public void shouldGetNodeByIdentifierPath() throws Exception {
- // Look up the node by the identifier path ...
- Node node = session.getNode(identifierPathFor("/a"));
- assertThat(node.getPath(), is("/a"));
-
- node = session.getNode(identifierPathFor("/a/b"));
- assertThat(node.getPath(), is("/a/b"));
-
- node = session.getNode(identifierPathFor("/"));
- assertThat(node.getPath(), is("/"));
- }
-
- @Test
- public void shouldCorrectlyDetermineIfItemExistsUsingPath() throws Exception {
- assertThat(session.itemExists("/"), is(true));
- assertThat(session.itemExists("/a"), is(true));
- assertThat(session.itemExists("/a/b"), is(true));
- }
-
- @Test
- public void shouldCorrectlyDetermineIfItemExistsUsingIdentifierPath() throws Exception {
- assertThat(session.itemExists(identifierPathFor("/")), is(true));
- assertThat(session.itemExists(identifierPathFor("/a")), is(true));
- assertThat(session.itemExists(identifierPathFor("/a/b")), is(true));
- }
-
- @Test
public void shouldProvidePropertiesByPath() throws Exception {
Item item = session.getItem("/a/b/booleanProperty");
assertThat(item, instanceOf(Property.class));
Index: pom.xml
===================================================================
--- pom.xml (revision 1859)
+++ pom.xml (working copy)
@@ -823,6 +823,7 @@
${basedir}/target
+ -Xmx128M