Index: .gitignore =================================================================== --- .gitignore (revision 2037) +++ .gitignore (working copy) @@ -52,6 +52,7 @@ /utils/modeshape-jpa-ddl-gen/target/ /deploy/jbossas/target/ +/deploy/jbossas/modeshape-jbossas-console/target/ /deploy/jbossas/modeshape-jbossas-service/target/ /deploy/jbossas/modeshape-jbossas-web-rest-war/target/ Index: docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml =================================================================== --- docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml (revision 2037) +++ docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml (working copy) @@ -862,23 +862,28 @@ final &LoginContext; loginContext = ...; Custom Node Type Registration Although the JSR-283 specification does not require support for registration and unregistration of custom types, ModeShape supports this extremely - useful feature. Custom node types can be added at startup, as noted above, at runtime through a ModeShape-specific interface that accepts CND files, or through the JSR-283 - node type template methods. - All three of these node type registration mechanisms are supported equally within ModeShape, although the CND approach for defining node types is recommended. + useful feature. Custom node types can be added at startup, as noted above, at runtime using the standard JCR API for managing node types, + or at runtime by reading CND files or Jackrabbit XML files. + These node type registration mechanisms are supported equally within ModeShape, although defining node types in standard CND files + is recommended for portability. ModeShape also supports defining custom node types to load at startup. This is discussed in more detail in the previous chapter. + + Managing Node Types Using the JCR API - Node types can be defined like so: + The JCR 2.0 API provides a mechanism for registering and unregistering node types. Registration is done by creating &NodeTypeTemplate; objects, + &NodeDefinitionTemplate; objects (for child node definitions), and &PropertyDefinitionTemplate; objects (for property definitions). + Use the setter methods to set the various attributes, and then register the node type definition with the &NodeTypeManager;: &Session; session = ... ; &Workspace; workspace = session.getWorkspace(); // Obtain the ModeShape-specific node type manager ... -&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) workspace.getNodeTypeManager(); +&NodeTypeManager; nodeTypeManager = workspace.getNodeTypeManager(); // Declare a mixin node type named "searchable" (with no namespace) &NodeTypeTemplate; nodeType = nodeTypeManager.createNodeTypeTemplate(); @@ -906,6 +911,28 @@ nodeTypeManager.registerNodeType(nodeType,false); Residual properties and child node definitions can also be defined simply by not calling setName on the template. + + ModeShape also supports a simple means of unregistering types, although it is not possible to unregister types that are + currently being used by nodes or as required primary types or supertypes of other types. Unused node types can be unregistered + with the following code, using the standard JCR 2.0 API: + +String[] unusedNodeTypeNames = ...; + +&Session; session = ... ; +&NodeTypeManager; nodeTypeManager = session.getWorkspace().getNodeTypeManager(); +nodeTypeManager.unregisterNodeTypes(unusedNodeTypeNames); + + + + + This approach is often used to register custom node types within an application, when the application knows the node type + definitions or retrieves these definitions from some persisted format (e.g., file, database, etc.). However, ModeShape + provides some utilities if you want to programmatically register node types defined in certain file formats. We'll see + in the next section how to use these. + + + + Reading JCR CND files Custom node types can be defined more succinctly through the CND file format defined by the JCR 2.0 specification. In fact, this is how JBoss ModeShape defines its built-in node types. An example CND file that declares the same node type as above would be: @@ -914,46 +941,52 @@ nodeTypeManager.registerNodeType(nodeType,false); - keywords (string) multiple + source (nt:file) = nt:file mandatory - This definition could then be registered as part of the repository configuration, using the &JcrConfiguration; class + This definition could then be registered as part of the repository configuration (see the previous chapter). Or, you can also - use a Session to declare the node types in a CND file, but this also requires ModeShape-specific interfaces and classes: - -String pathToCndFileInClassLoader = ...; -&CndNodeTypeSource; nodeTypeSource = new &CndNodeTypeSource;(pathToCndFileInClassLoader); + use a Session to programmatically register the node types in a CND file, but this requires ModeShape-specific class to read this file: +&CndNodeTypeReader; reader = new &CndNodeTypeReader;(); +reader.read(cndFile); // from file, file system path, classpath resource, URL, etc. -for (&Problem; problem : nodeTypeSource.getProblems()) { - System.err.println(problem); -} -if (!nodeTypeSource.isValid()) { - throw new IllegalStateException("Problems loading node types"); -} - -&Session; session = ... ; -// Obtain the ModeShape-specific node type manager ... -&Workspace; workspace = session.getWorkspace(); -&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) workspace.getNodeTypeManager(); -nodeTypeManager.registerNodeTypes(nodeTypeSource); - +if (!reader.getProblems().isEmpty()) { + for (&Problem; problem : nodeTypeSource.getProblems()) { + // report or record problem + } +} else { + boolean allowUpdate = ... + &Session; session = ... + &NodeTypeManager; nodeTypeManager = session.getWorkspace().getNodeTypeManager(); + nodeTypeManager.registerNodeTypes(reader.getNodeTypes(), allowUpdate); +} - The &CndNodeTypeSource; class actually implements the &JcrNodeTypeSource; interface, so other implementations can actually be defined. - For more information, see the JavaDoc for &JcrNodeTypeSource;. - - - ModeShape also supports a simple means of unregistering types, although it is not possible to unregister types that are - currently being used by nodes or as required primary types or supertypes of other types. Unused node types can be unregistered - with the following code: - -String unusedNodeTypeName = ...; + The &CndNodeTypeReader; class provides a number of read(...) methods that accept &File;s, paths to files on the file system, + the names of resources on the classpath, &URLs;, and &InputStream;s. For details, see the JavaDoc for &CndNodeTypeReader;. + If you have multiple CND files, you can either call read(...) multiple times before + registering (as long as the CND files don't contain duplicate node type definitions), or you can simply create and use a new reader + for each CND file. The choice is yours. + + + + Reading Jackrabbit XML Node Type Files + + ModeShape also provides a class that reads the node types defined in a Jackrabbit XML format. This is useful if you've been using Jackrabbit, + have defined your custom node types in the Jackrabbit-specific format, but want to switch to ModeShape and don't want to have to manually + convert your node types in the standard CND format. This class is used almost identically to the &CndNodeTypeReader; class described above: +&JackrabbitXmlNodeTypeReader; reader = new &JackrabbitXmlNodeTypeReader;(); +reader.read(cndFile); // from file, file system path, classpath resource, URL, etc. -&Session; session = ... ; -// Obtain the ModeShape-specific node type manager ... -&Workspace; workspace = session.getWorkspace(); -&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) workspace.getNodeTypeManager(); -nodeTypeManager.unregisterNodeType(Collections.singleton(unusedNodeTypeName)); - - - - +if (!reader.getProblems().isEmpty()) { + for (&Problem; problem : nodeTypeSource.getProblems()) { + // report or record problem + } +} else { + boolean allowUpdate = ... + &Session; session = ... + &NodeTypeManager; nodeTypeManager = session.getWorkspace().getNodeTypeManager(); + nodeTypeManager.registerNodeTypes(reader.getNodeTypes(), allowUpdate); +} + + + Summary Index: docs/reference/src/main/docbook/en-US/custom.dtd =================================================================== --- docs/reference/src/main/docbook/en-US/custom.dtd (revision 2037) +++ docs/reference/src/main/docbook/en-US/custom.dtd (working copy) @@ -105,6 +105,11 @@ QueryResult"> QueryObjectModel"> QueryObjectModelFactory"> +NodeTypeManager"> +NodeTypeTemplate"> +PropertyDefinitionTemplate"> +NodeDefinitionTemplate"> +NodeTypeDefinition"> @@ -237,12 +242,8 @@ JndiRepositoryFactory"> SecurityContextCredentials"> JcrNodeTypeManager"> -NodeTypeTemplate"> -PropertyDefinitionTemplate"> -NodeDefinitionTemplate"> -NodeTypeDefinition"> -JcrNodeTypeSource"> -CndNodeTypeSource"> +CndNodeTypeReader"> +JackrabbitXmlNodeTypeReader"> Index: modeshape-jcr/src/main/java/org/modeshape/jcr/CndNodeTypeReader.java new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/CndNodeTypeReader.java (working copy) @@ -0,0 +1,187 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.jcr.Session; +import org.modeshape.cnd.CndImporter; +import org.modeshape.graph.ExecutionContext; +import org.modeshape.graph.Graph; +import org.modeshape.graph.Location; +import org.modeshape.graph.Subgraph; +import org.modeshape.graph.io.Destination; +import org.modeshape.graph.property.Path; + +/** + * A class that reads files in the standard CND format defined by the JCR 2.0 specification. + *

+ * Typically, the class will be used like this: + * + *

+ * CndNodeTypeReader reader = new CndNodeTypeReader();
+ * reader.read(file); // or stream or resource file
+ * 
+ * if (!reader.getProblems().isEmpty()) {
+ *     // Report problems
+ * } else {
+ *     boolean allowUpdate = false;
+ *     session.getWorkspace().getNodeTypeManager().registerNodeTypes(reader.getNodeTypes(), allowUpdate);
+ * }
+ * 
+ * + *

+ */ +public class CndNodeTypeReader extends GraphNodeTypeReader { + + /** + * Create a new node type factory that reads CND files. + * + * @param session the session that will be used to register the node types; may not be null + */ + public CndNodeTypeReader( Session session ) { + super(session); + } + + /** + * Create a new node type factory that reads CND files. + * + * @param context the context that will be used to load the node types; may not be null + */ + public CndNodeTypeReader( ExecutionContext context ) { + super(context); + } + + /** + * Import the node types from the supplied stream and add all of the node type definitions to this factory's list. + * + * @param stream the stream containing the node types + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + * @throws IOException if there is a problem reading from the supplied stream + */ + @Override + public void read( InputStream stream, + String resourceName ) throws IOException { + super.read(stream, resourceName); + } + + /** + * Import the node types from the supplied file and add all of the node type definitions to this factory's list. + * + * @param file the file containing the node types + * @throws IOException if there is a problem reading from the supplied stream + */ + @Override + public void read( File file ) throws IOException { + super.read(file); + } + + /** + * Import the node types from the file at the supplied URL and add all of the node type definitions to this factory's list. + * + * @param url the URL to the file containing the node types + * @throws IOException if there is a problem reading from the supplied stream + */ + @Override + public void read( URL url ) throws IOException { + super.read(url); + } + + /** + * Import the node types from the supplied file and add all of the node type definitions to this factory's list. + * + * @param resourceFile the name of the resource file on the classpath containing the node types + * @throws IOException if there is a problem reading from the supplied resource + */ + @Override + public void read( String resourceFile ) throws IOException { + super.read(resourceFile); + } + + /** + * Import the node types from the supplied string and add all of the node type definitions to this factory's list. + * + * @param content the string containing the node types + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @Override + public void read( String content, + String resourceName ) { + super.read(content, resourceName); + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param graph the graph containing the standard ModeShape CND content + * @param parentOfTypes the path to the parent of the node type definition nodes + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @Override + public void read( Graph graph, + Path parentOfTypes, + String resourceName ) { + super.read(graph, parentOfTypes, resourceName); + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param subgraph the subgraph containing the standard ModeShape CND content + * @param locationOfParent the location to the parent of the node type definition nodes + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @Override + public void read( Subgraph subgraph, + Location locationOfParent, + String resourceName ) { + super.read(subgraph, locationOfParent, resourceName); + } + + protected void readBuiltInTypes() throws IOException { + read("/org/modeshape/jcr/jsr_283_builtins.cnd"); + read("/org/modeshape/jcr/modeshape_builtins.cnd"); + } + + /** + * {@inheritDoc} + * + * @see org.modeshape.jcr.GraphNodeTypeReader#importFrom(org.modeshape.graph.io.Destination, + * org.modeshape.graph.property.Path, java.lang.String, java.lang.String) + */ + @Override + protected void importFrom( Destination destination, + Path path, + String content, + String resourceName ) throws Exception { + CndImporter importer = new CndImporter(destination, pathFactory.createRootPath()); + importer.importFrom(content, problems, resourceName); + } +} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/CndNodeTypeSource.java deleted file mode 100644 =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/CndNodeTypeSource.java (revision 2037) +++ /dev/null (working copy) @@ -1,143 +0,0 @@ -/* - * ModeShape (http://www.modeshape.org) - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. Some portions may be licensed - * to Red Hat, Inc. under one or more contributor license agreements. - * See the AUTHORS.txt file in the distribution for a full listing of - * individual contributors. - * - * ModeShape is free software. Unless otherwise indicated, all code in ModeShape - * is licensed to you under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * ModeShape is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.modeshape.jcr; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import net.jcip.annotations.Immutable; -import org.modeshape.cnd.CndImporter; -import org.modeshape.common.collection.ImmutableProblems; -import org.modeshape.common.collection.Problems; -import org.modeshape.common.collection.SimpleProblems; -import org.modeshape.graph.ExecutionContext; -import org.modeshape.graph.Graph; -import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; -import org.modeshape.graph.io.Destination; -import org.modeshape.graph.io.GraphBatchDestination; -import org.modeshape.graph.property.PathFactory; - -/** - * Class to parse one or more Compact Node Definition (CND) files containing custom node type definitions into a format that can - * be registered with the {@link JcrNodeTypeManager}. - *

- * The class contains methods for determining whether the CND files were parsed successfully and what errors occurred. Typically, - * the class will be used like this: - * - *

- * try {
- *  String[] cndFilePaths = // The URIs for the resource files on the classpath
- *  JcrNodeTypeSource nodeTypeSource = new CndNodeTypeSource(cndFilePaths);
- *  
- *  if (!nodeTypeSource.isValid()) {
- *      Problems problems = nodeTypeSource.getProblems();
- *      // Report problems
- *  }
- *  else {
- *      jcrNodeTypeManager.registerNodeTypes(nodeTypeSource);
- *  }
- * }
- * catch (IOException ioe) {
- *  System.err.println("Could not find one of the CND files.");
- *  ioe.printStackTrace();
- * }
- * 
- * 
- * - *

- */ -@Immutable -public class CndNodeTypeSource implements JcrNodeTypeSource { - - private final Graph graph; - private final Problems problems; - - /** - * Creates a new {@link JcrNodeTypeSource} with based on the CND file with the given resource name. - * - * @param resourceName the name of the resource; this resource must be on the classpath - * @throws IOException if an error loading or reading the resource occurs - */ - public CndNodeTypeSource( String resourceName ) throws IOException { - this(new String[] {resourceName}); - } - - /** - * Creates a new {@link JcrNodeTypeSource} based on the CND files at the given resource names. - * - * @param resourceNames the name of the resources to load; these resources must be on the classpath - * @throws IOException if an error loading or reading the any of the resources occurs - */ - public CndNodeTypeSource( String resourceNames[] ) throws IOException { - - Problems problems = new SimpleProblems(); - - // Graph creation requires a context, but there are no security implications for this and namespace mappings are - // specified in the CND file itself - ExecutionContext context = new ExecutionContext(); - PathFactory pathFactory = context.getValueFactories().getPathFactory(); - InMemoryRepositorySource source = new InMemoryRepositorySource(); - source.setName("CND Import Source"); - this.graph = Graph.create(source, context); - for (String resourceName : Arrays.asList(resourceNames)) { - Graph.Batch batch = graph.batch(); - Destination destination = new GraphBatchDestination(batch); - CndImporter importer = new CndImporter(destination, pathFactory.createRootPath()); - InputStream is = getClass().getResourceAsStream(resourceName); - - // This submits the batch - importer.importFrom(is, problems, resourceName); - } - this.problems = new ImmutableProblems(problems); - } - - /** - * Returns true if no errors were encountered while parsing the CND file or files - * - * @return true if no errors were encountered while parsing the CND file or files - */ - public boolean isValid() { - return !problems.hasErrors(); - } - - /** - * Returns the problems (if any) that were encountered parsing the CND files. Node type registration errors or warnings will - * NOT be added to this set of problems. - * - * @return returns the problems (if any) that were encountered parsing the CND files. - */ - public Problems getProblems() { - return problems; - } - - /** - * {@inheritDoc} - * - * @see org.modeshape.jcr.JcrNodeTypeSource#getNodeTypes() - */ - public final Graph getNodeTypes() { - return graph; - } - -} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java (working copy) @@ -0,0 +1,555 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.jcr.PropertyType; +import javax.jcr.Session; +import javax.jcr.Value; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NodeDefinitionTemplate; +import javax.jcr.nodetype.NodeTypeDefinition; +import javax.jcr.nodetype.NodeTypeTemplate; +import javax.jcr.nodetype.PropertyDefinitionTemplate; +import javax.jcr.version.OnParentVersionAction; +import net.jcip.annotations.NotThreadSafe; +import org.modeshape.common.collection.Problems; +import org.modeshape.common.collection.SimpleProblems; +import org.modeshape.common.util.CheckArg; +import org.modeshape.common.util.IoUtil; +import org.modeshape.graph.ExecutionContext; +import org.modeshape.graph.Graph; +import org.modeshape.graph.Location; +import org.modeshape.graph.Subgraph; +import org.modeshape.graph.SubgraphNode; +import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; +import org.modeshape.graph.io.Destination; +import org.modeshape.graph.io.GraphBatchDestination; +import org.modeshape.graph.property.Name; +import org.modeshape.graph.property.NameFactory; +import org.modeshape.graph.property.Path; +import org.modeshape.graph.property.PathFactory; +import org.modeshape.graph.property.Property; +import org.modeshape.graph.property.ValueFactories; +import org.modeshape.graph.property.ValueFactory; +import org.modeshape.graph.property.basic.LocalNamespaceRegistry; + +/** + * A base class for loading content into a graph with the standard format used by ModeShape. + *

+ * The root node of the graph should have zero or more children. Each child of the root node represents a type to be registered + * and the name of the node should be the name of the node type to be registered. Additionally, any facets of the node type that + * are specified should be set in a manner consistent with the JCR specification for the {@code nt:nodeType} built-in node type. + * The {@code jcr:primaryType} property does not need to be set on these nodes, but the nodes must be semantically valid as if the + * {@code jcr:primaryType} property was set. + *

+ *

+ * Each node type node may have zero or more children, each with the name {@code jcr:propertyDefinition} or {@code + * jcr:childNodeDefinition}, as per the definition of the {@code nt:nodeType} built-in type. Each property definition and child + * node definition must obey the semantics of {@code jcr:propertyDefinition} and {@code jcr:childNodeDefinition} respectively + * However these nodes also do not need to have the {@code jcr:primaryType} property set. + *

+ *

+ * For example, one valid graph is: + * + *

+ * <root>
+ * +---- test:testMixinType
+ *        +--- jcr:nodeTypeName               =  test:testMixinType  (PROPERTY)
+ *        +--- jcr:isMixin                    =  true                (PROPERTY)    
+ *        +--- jcr:childNodeDefinition                               (CHILD NODE)
+ *        |     +--- jcr:name                 =  test:childNodeA     (PROPERTY)
+ *        |     +--- jcr:mandatory            =  true                (PROPERTY)
+ *        |     +--- jcr:autoCreated          =  true                (PROPERTY)
+ *        |     +--- jcr:defaultPrimaryType   =  nt:base             (PROPERTY)
+ *        |     +--- jcr:requiredPrimaryTypes =  nt:base             (PROPERTY)
+ *        +--- jcr:propertyDefinition                                (CHILD NODE)
+ *              +--- jcr:name                 =  test:propertyA      (PROPERTY)
+ *              +--- jcr:multiple             =  true                (PROPERTY)
+ *              +--- jcr:requiredType         =  String              (PROPERTY)
+ * 
+ * + * This graph (when registered) would create a mixin node named "test:testMixinType" with a mandatory, autocreated child node + * named "test:childNodeA" with a default and required primary type of "nt:base" and a multi-valued string property named + * "test:propertyA". + *

+ */ +@NotThreadSafe +abstract class GraphNodeTypeReader implements Iterable { + + private static final Map PROPERTY_TYPE_VALUES_FROM_NAME; + + static { + Map temp = new HashMap(); + + temp.put(PropertyType.TYPENAME_BINARY.toUpperCase(), PropertyType.BINARY); + temp.put(PropertyType.TYPENAME_BOOLEAN.toUpperCase(), PropertyType.BOOLEAN); + temp.put(PropertyType.TYPENAME_DATE.toUpperCase(), PropertyType.DATE); + temp.put(PropertyType.TYPENAME_DECIMAL.toUpperCase(), PropertyType.DECIMAL); + temp.put(PropertyType.TYPENAME_DOUBLE.toUpperCase(), PropertyType.DOUBLE); + temp.put(PropertyType.TYPENAME_LONG.toUpperCase(), PropertyType.LONG); + temp.put(PropertyType.TYPENAME_NAME.toUpperCase(), PropertyType.NAME); + temp.put(PropertyType.TYPENAME_PATH.toUpperCase(), PropertyType.PATH); + temp.put(PropertyType.TYPENAME_STRING.toUpperCase(), PropertyType.STRING); + temp.put(PropertyType.TYPENAME_REFERENCE.toUpperCase(), PropertyType.REFERENCE); + temp.put(PropertyType.TYPENAME_WEAKREFERENCE.toUpperCase(), PropertyType.WEAKREFERENCE); + temp.put(PropertyType.TYPENAME_UNDEFINED.toUpperCase(), PropertyType.UNDEFINED); + temp.put(PropertyType.TYPENAME_URI.toUpperCase(), PropertyType.URI); + + PROPERTY_TYPE_VALUES_FROM_NAME = Collections.unmodifiableMap(temp); + } + + protected final Problems problems = new SimpleProblems(); + protected final List types = new ArrayList(); + protected final List immutableTypes = Collections.unmodifiableList(types); + protected final ExecutionContext context; + protected final ValueFactories valueFactories; + protected final PathFactory pathFactory; + protected final NameFactory nameFactory; + protected final ValueFactory booleanFactory; + protected final ValueFactory stringFactory; + protected final Path root; + + /** + * Create a new node type factory that reads CND files. + * + * @param session the session that will be used to register the node types; may not be null and must be a ModeShape Session. + */ + protected GraphNodeTypeReader( Session session ) { + this(CheckArg.getInstanceOf(session, JcrSession.class, "session").getExecutionContext()); + } + + /** + * Create a new node type factory that reads CND files. + * + * @param executionContext the session that will be used to load the node types; may not be null and must be a ModeShape + * Session. + */ + protected GraphNodeTypeReader( ExecutionContext executionContext ) { + LocalNamespaceRegistry localRegistry = new LocalNamespaceRegistry(executionContext.getNamespaceRegistry()); + context = executionContext.with(localRegistry); + valueFactories = context.getValueFactories(); + pathFactory = valueFactories.getPathFactory(); + nameFactory = valueFactories.getNameFactory(); + booleanFactory = valueFactories.getBooleanFactory(); + stringFactory = valueFactories.getStringFactory(); + root = pathFactory.createRootPath(); + } + + /** + * Import the node types from the supplied stream and add all of the node type definitions to this factory's list. + * + * @param stream the stream containing the node types + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + * @throws IOException if there is a problem reading from the supplied stream + */ + public void read( InputStream stream, + String resourceName ) throws IOException { + read(IoUtil.read(stream), resourceName); + } + + /** + * Import the node types from the supplied file and add all of the node type definitions to this factory's list. + * + * @param file the file containing the node types + * @throws IOException if there is a problem reading from the supplied stream + */ + public void read( File file ) throws IOException { + read(IoUtil.read(file), file.getCanonicalPath()); + } + + /** + * Import the node types from the file at the supplied URL and add all of the node type definitions to this factory's list. + * + * @param url the URL to the file containing the node types + * @throws IOException if there is a problem reading from the supplied stream + */ + public void read( URL url ) throws IOException { + InputStream stream = url.openStream(); + try { + read(IoUtil.read(stream), url.toString()); + } finally { + stream.close(); + } + } + + /** + * Import the node types from the supplied file and add all of the node type definitions to this factory's list. + * + * @param resourceFile the name of the resource file on the classpath containing the node types + * @throws IOException if there is a problem reading from the supplied resource + */ + public void read( String resourceFile ) throws IOException { + InputStream stream = getClass().getResourceAsStream(resourceFile); + if (stream != null) { + try { + read(IoUtil.read(stream), resourceFile); + } finally { + stream.close(); + } + } + } + + /** + * Import the node types from the supplied string and add all of the node type definitions to this factory's list. + * + * @param content the string containing the node types + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @SuppressWarnings( "cast" ) + public void read( String content, + String resourceName ) { + InMemoryRepositorySource source = new InMemoryRepositorySource(); + source.setName("Node Type Import Source"); + Graph graph = Graph.create(source, context); + + // Create the batch and load the graph ... + Graph.Batch batch = graph.batch(); + Destination destination = new GraphBatchDestination(batch); + try { + importFrom(destination, root, content, resourceName); + List types = readTypesFrom(graph, root); + this.types.addAll(types); + } catch (Throwable t) { + problems.addError(t, JcrI18n.errorImportingNodeTypeContent, (Object)resourceName, t.getMessage()); + } + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param graph the graph containing the standard ModeShape CND content + * @param parentOfTypes the path to the parent of the node type definition nodes + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + public void read( Graph graph, + Path parentOfTypes, + String resourceName ) { + this.types.addAll(readTypesFrom(graph, parentOfTypes)); + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param subgraph the subgraph containing the standard ModeShape CND content + * @param locationOfParent the location to the parent of the node type definition nodes + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + public void read( Subgraph subgraph, + Location locationOfParent, + String resourceName ) { + this.types.addAll(readTypesFrom(subgraph, locationOfParent)); + } + + /** + * Get the problems where warnings and error messages were recorded by this factory. + * + * @return the problems; never null + */ + public Problems getProblems() { + return problems; + } + + /** + * Returns the node type definitions created by this factory. + * + * @return the {@link NodeTypeDefinition}s + */ + public NodeTypeDefinition[] getNodeTypeDefinitions() { + return types.toArray(new NodeTypeDefinition[types.size()]); + } + + /** + * {@inheritDoc} + * + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return immutableTypes.iterator(); + } + + protected List readTypesFrom( Graph graph, + Path parentOfTypes ) { + Subgraph subgraph = graph.getSubgraphOfDepth(5).at(parentOfTypes); + return readTypesFrom(subgraph, subgraph.getLocation()); + } + + protected List readTypesFrom( Subgraph nodeTypeSubgraph, + Location locationOfParentOfNodeTypes ) { + List nodeTypeLocations = nodeTypeSubgraph.getNode(locationOfParentOfNodeTypes).getChildren(); + List results = new ArrayList(nodeTypeLocations.size()); + + for (Location location : nodeTypeLocations) { + SubgraphNode nodeTypeNode = nodeTypeSubgraph.getNode(location); + assert location.getPath() != null; + try { + NodeTypeDefinition nodeType = nodeTypeFrom(nodeTypeNode, nodeTypeSubgraph); + results.add(nodeType); + } catch (ConstraintViolationException e) { + String resource = stringFactory.create(locationOfParentOfNodeTypes.getPath()); + problems.addError(e, JcrI18n.errorImportingNodeTypeContent, resource, e.getMessage()); + } + } + return results; + } + + @SuppressWarnings( "unchecked" ) + protected NodeTypeTemplate nodeTypeFrom( SubgraphNode nodeTypeNode, + Subgraph subgraph ) throws ConstraintViolationException { + List children = nodeTypeNode.getChildren(); + + String name = readString(nodeTypeNode, JcrLexicon.NODE_TYPE_NAME, null); + String primaryItemName = readString(nodeTypeNode, JcrLexicon.PRIMARY_ITEM_NAME, null); + + boolean mixin = readBoolean(nodeTypeNode, JcrLexicon.IS_MIXIN, false); + boolean isAbstract = readBoolean(nodeTypeNode, JcrLexicon.IS_ABSTRACT, false); + boolean queryable = readBoolean(nodeTypeNode, JcrLexicon.IS_QUERYABLE, true); + boolean orderableChildNodes = readBoolean(nodeTypeNode, JcrLexicon.HAS_ORDERABLE_CHILD_NODES, false); + List supertypes = readStrings(nodeTypeNode, JcrLexicon.SUPERTYPES); + + NodeTypeTemplate template = new JcrNodeTypeTemplate(context); + template.setAbstract(isAbstract); + template.setDeclaredSuperTypeNames(supertypes.toArray(new String[supertypes.size()])); + template.setMixin(mixin); + template.setName(name); + template.setOrderableChildNodes(orderableChildNodes); + template.setPrimaryItemName(primaryItemName); + template.setQueryable(queryable); + + for (Location childLocation : children) { + if (JcrLexicon.PROPERTY_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) { + template.getPropertyDefinitionTemplates().add(propertyDefinitionFrom(subgraph, childLocation)); + } else if (JcrLexicon.CHILD_NODE_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) { + template.getNodeDefinitionTemplates().add(childNodeDefinitionFrom(subgraph, childLocation)); + } else { + throw new IllegalStateException("Unexpected child of node type at: " + childLocation); + } + } + + return template; + } + + protected PropertyDefinitionTemplate propertyDefinitionFrom( Subgraph nodeTypeGraph, + Location propertyLocation ) throws ConstraintViolationException { + SubgraphNode propertyDefinitionNode = nodeTypeGraph.getNode(propertyLocation); + + String name = readString(propertyDefinitionNode, JcrLexicon.NAME, null); + String onParentVersionName = readString(propertyDefinitionNode, + JcrLexicon.ON_PARENT_VERSION, + OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY)); + int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName); + int requiredType = PROPERTY_TYPE_VALUES_FROM_NAME.get(readString(propertyDefinitionNode, JcrLexicon.REQUIRED_TYPE, null)); + + boolean mandatory = readBoolean(propertyDefinitionNode, JcrLexicon.MANDATORY, false); + boolean multiple = readBoolean(propertyDefinitionNode, JcrLexicon.MULTIPLE, false); + boolean autoCreated = readBoolean(propertyDefinitionNode, JcrLexicon.AUTO_CREATED, false); + boolean isProtected = readBoolean(propertyDefinitionNode, JcrLexicon.PROTECTED, false); + boolean isSearchable = readBoolean(propertyDefinitionNode, JcrLexicon.IS_FULL_TEXT_SEARCHABLE, true); + boolean isOrderable = readBoolean(propertyDefinitionNode, JcrLexicon.IS_QUERY_ORDERABLE, true); + List defaultValues = readValues(propertyDefinitionNode, JcrLexicon.DEFAULT_VALUES, requiredType); + List constraints = readStrings(propertyDefinitionNode, JcrLexicon.VALUE_CONSTRAINTS); + List queryOps = readStrings(propertyDefinitionNode, JcrLexicon.QUERY_OPERATORS); + + PropertyDefinitionTemplate template = new JcrPropertyDefinitionTemplate(context); + template.setName(name); + template.setAutoCreated(autoCreated); + template.setMandatory(mandatory); + template.setMultiple(multiple); + template.setProtected(isProtected); + template.setFullTextSearchable(isSearchable); + template.setAvailableQueryOperators(queryOps.toArray(new String[queryOps.size()])); + template.setQueryOrderable(isOrderable); + template.setProtected(isProtected); + template.setOnParentVersion(onParentVersion); + template.setDefaultValues(defaultValues.toArray(new Value[defaultValues.size()])); + template.setRequiredType(requiredType); + template.setValueConstraints(constraints.toArray(new String[constraints.size()])); + return template; + } + + protected NodeDefinitionTemplate childNodeDefinitionFrom( Subgraph nodeTypeGraph, + Location childNodeLocation ) throws ConstraintViolationException { + SubgraphNode childNodeDefinitionNode = nodeTypeGraph.getNode(childNodeLocation); + + String childNodeName = readString(childNodeDefinitionNode, JcrLexicon.NAME, null); + String defaultPrimaryTypeName = readString(childNodeDefinitionNode, JcrLexicon.DEFAULT_PRIMARY_TYPE, null); + String onParentVersionName = readString(childNodeDefinitionNode, + JcrLexicon.ON_PARENT_VERSION, + OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY)); + int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName); + + boolean mandatory = readBoolean(childNodeDefinitionNode, JcrLexicon.MANDATORY, false); + boolean allowsSns = readBoolean(childNodeDefinitionNode, JcrLexicon.SAME_NAME_SIBLINGS, false); + boolean autoCreated = readBoolean(childNodeDefinitionNode, JcrLexicon.AUTO_CREATED, false); + boolean isProtected = readBoolean(childNodeDefinitionNode, JcrLexicon.PROTECTED, false); + List requiredTypes = readStrings(childNodeDefinitionNode, JcrLexicon.REQUIRED_PRIMARY_TYPES); + + NodeDefinitionTemplate template = new JcrNodeDefinitionTemplate(context); + template.setName(childNodeName); + template.setAutoCreated(autoCreated); + template.setMandatory(mandatory); + template.setSameNameSiblings(allowsSns); + template.setProtected(isProtected); + template.setOnParentVersion(onParentVersion); + template.setDefaultPrimaryTypeName(defaultPrimaryTypeName); + template.setRequiredPrimaryTypeNames(requiredTypes.toArray(new String[requiredTypes.size()])); + return template; + } + + protected Name nameFrom( SubgraphNode node ) { + return node.getLocation().getPath().getLastSegment().getName(); + } + + protected Name name( String name ) { + return nameFactory.create(name); + } + + protected String string( Object value ) { + return stringFactory.create(value); + } + + protected boolean readBoolean( SubgraphNode node, + String propertyName, + boolean defaultValue ) { + return readBoolean(node, nameFactory.create(propertyName), defaultValue); + } + + protected boolean readBoolean( SubgraphNode node, + Name propertyName, + boolean defaultValue ) { + Property property = node.getProperty(propertyName); + return property != null ? booleanFactory.create(property.getFirstValue()) : defaultValue; + } + + protected String readString( SubgraphNode node, + String propertyName, + String defaultValue ) { + return readString(node, nameFactory.create(propertyName), defaultValue); + } + + protected String readString( SubgraphNode node, + Name propertyName, + String defaultValue ) { + Property property = node.getProperty(propertyName); + return property != null ? stringFactory.create(property.getFirstValue()) : defaultValue; + } + + protected List readStrings( SubgraphNode node, + String propertyName ) { + return readStrings(node, nameFactory.create(propertyName)); + } + + protected List readStrings( SubgraphNode node, + Name propertyName ) { + List results = new ArrayList(); + Property property = node.getProperty(propertyName); + if (property != null) { + for (Object value : property) { + String str = stringFactory.create(value); + if (str != null && str.length() != 0) results.add(str); + } + } + return results; + } + + protected List readValues( SubgraphNode node, + Name propertyName, + int requiredType ) { + List results = readStrings(node, propertyName); + List values = new ArrayList(results.size()); + for (String result : results) { + values.add(new JcrValue(valueFactories, null, requiredType, result)); + } + return values; + } + + protected Name readName( SubgraphNode node, + String propertyName, + Name defaultValue ) { + return readName(node, nameFactory.create(propertyName), defaultValue); + } + + protected Name readName( SubgraphNode node, + Name propertyName, + Name defaultValue ) { + Property property = node.getProperty(propertyName); + if (property != null && !property.isEmpty()) { + String firstValue = stringFactory.create(property.getFirstValue()); + if (firstValue != null && firstValue.trim().length() != 0) { + return valueFactories.getNameFactory().create(firstValue); + } + } + return defaultValue; + } + + protected List readNames( SubgraphNode node, + String propertyName, + Name defaultIfNone ) { + return readNames(node, nameFactory.create(propertyName), defaultIfNone); + } + + protected List readNames( SubgraphNode node, + Name propertyName, + Name defaultIfNone ) { + List results = new ArrayList(); + Property property = node.getProperty(propertyName); + if (property != null) { + for (Object value : property) { + Name name = nameFactory.create(value); + if (name != null) results.add(name); + } + } + if (results.isEmpty() && defaultIfNone != null) results.add(defaultIfNone); + return results; + } + + /** + * Method that loads into the graph destination the content containing the node type definitions. + * + * @param graphDestination + * @param path + * @param content + * @param resourceName + * @throws Exception if there is a problem importing from the content; this will be automatically recorded in the problems + */ + protected abstract void importFrom( Destination graphDestination, + Path path, + String content, + String resourceName ) throws Exception; + +} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JackrabbitXmlNodeTypeReader.java new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JackrabbitXmlNodeTypeReader.java (working copy) @@ -0,0 +1,642 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import javax.jcr.Session; +import org.modeshape.common.collection.Problems; +import org.modeshape.common.util.CheckArg; +import org.modeshape.common.util.IoUtil; +import org.modeshape.graph.ExecutionContext; +import org.modeshape.graph.Graph; +import org.modeshape.graph.JcrLexicon; +import org.modeshape.graph.Location; +import org.modeshape.graph.Subgraph; +import org.modeshape.graph.SubgraphNode; +import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; +import org.modeshape.graph.io.Destination; +import org.modeshape.graph.property.Name; +import org.modeshape.graph.property.NameFactory; +import org.modeshape.graph.property.Path; +import org.modeshape.graph.property.PathFactory; +import org.modeshape.graph.property.PathNotFoundException; +import org.modeshape.graph.property.Property; +import org.modeshape.graph.property.PropertyFactory; +import org.modeshape.graph.property.ValueFactories; +import org.xml.sax.SAXException; + +/** + * A class that reads node types from Jackrabbit XML files. + *

+ * Typically, the class will be used like this: + * + *

+ * // Instantiate the reader and load one or more files ... 
+ * JackrabbitXmlNodeTypeReader reader = new JackrabbitXmlNodeTypeReader();
+ * reader.read(file); // or stream or resource file
+ * 
+ * if (!reader.getProblems().isEmpty()) {
+ *     // Report problems
+ * } else {
+ *     // Use the standard JCR API to register the loaded node types ... 
+ *     boolean allowUpdate = false;
+ *     session.getWorkspace().getNodeTypeManager().registerNodeTypes(reader.getNodeTypes(), allowUpdate);
+ * }
+ * 
+ * + *

+ *

+ * The format of the XML is defined by this DTD: + * + *

+ * <!ELEMENT nodeTypes (nodeType)*>
+ *     <!ELEMENT nodeType (supertypes?|propertyDefinition*|childNodeDefinition*)>
+ * 
+ *     <!ATTLIST nodeType
+ *             name CDATA #REQUIRED
+ *             isMixin (true|false) #REQUIRED
+ *              hasOrderableChildNodes (true|false) #REQUIRED
+ *             primaryItemName CDATA #REQUIRED
+ *         >
+ *     <!ELEMENT supertypes (supertype+)>
+ *     <!ELEMENT supertype (CDATA)>
+ * 
+ *     <!ELEMENT propertyDefinition (valueConstraints?|defaultValues?)>
+ *     <!ATTLIST propertyDefinition
+ *             name CDATA #REQUIRED
+ *             requiredType (String|Date|Path|Name|Reference|Binary|Double|Long|Boolean|undefined) #REQUIRED
+ *             autoCreated (true|false) #REQUIRED
+ *             mandatory (true|false) #REQUIRED
+ *             onParentVersion (COPY|VERSION|INITIALIZE|COMPUTE|IGNORE|ABORT) #REQUIRED
+ *             protected (true|false) #REQUIRED
+ *             multiple  (true|false) #REQUIRED
+ *         >
+ *     <!ELEMENT valueConstraints (valueConstraint+)>
+ *     <!ELEMENT valueConstraint (CDATA)>
+ *     <!ELEMENT defaultValues (defaultValue+)>
+ *     <!ELEMENT defaultValue (CDATA)>
+ * 
+ *     <!ELEMENT childNodeDefinition (requiredPrimaryTypes)>
+ *     <!ATTLIST childNodeDefinition
+ *             name CDATA #REQUIRED
+ *             defaultPrimaryType  CDATA #REQUIRED
+ *             autoCreated (true|false) #REQUIRED
+ *             mandatory (true|false) #REQUIRED
+ *             onParentVersion (COPY|VERSION|INITIALIZE|COMPUTE|IGNORE|ABORT) #REQUIRED
+ *             protected (true|false) #REQUIRED
+ *             sameNameSiblings (true|false) #REQUIRED
+ *         >
+ *     <!ELEMENT requiredPrimaryTypes (requiredPrimaryType+)>
+ *     <!ELEMENT requiredPrimaryType (CDATA)>
+ * 
+ * 
+ */ +public class JackrabbitXmlNodeTypeReader extends GraphNodeTypeReader { + + /** + * Create a new node type factory that reads the node types from Jackrabbit XML files. + * + * @param session the session that will be used to register the node types; may not be null + */ + public JackrabbitXmlNodeTypeReader( Session session ) { + super(session); + } + + /** + * Create a new node type factory that reads the node types from Jackrabbit XML files. + * + * @param context the context that will be used to load the node types; may not be null + */ + public JackrabbitXmlNodeTypeReader( ExecutionContext context ) { + super(context); + } + + /** + * Import the node types from the supplied stream and add all of the node type definitions to this factory's list. + * + * @param stream the stream containing the CND content + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + * @throws IOException if there is a problem reading from the supplied stream + */ + @Override + public void read( InputStream stream, + String resourceName ) throws IOException { + super.read(stream, resourceName); + } + + /** + * Import the node types from the supplied file and add all of the node type definitions to this factory's list. + * + * @param file the file containing the CND content + * @throws IOException if there is a problem reading from the supplied stream + */ + @Override + public void read( File file ) throws IOException { + super.read(file); + } + + /** + * Import the node types from the file at the supplied URL and add all of the node type definitions to this factory's list. + * + * @param url the URL to the file containing the node types + * @throws IOException if there is a problem reading from the supplied stream + */ + @Override + public void read( URL url ) throws IOException { + super.read(url); + } + + /** + * Import the node types from the supplied file and add all of the node type definitions to this factory's list. + * + * @param resourceFile the name of the resource file on the classpath containing the node types + * @throws IOException if there is a problem reading from the supplied resource + */ + @Override + public void read( String resourceFile ) throws IOException { + super.read(resourceFile); + } + + /** + * Import the node types from the supplied string and add all of the node type definitions to this factory's list. + * + * @param content the string containing the CND content + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @Override + public void read( String content, + String resourceName ) { + super.read(content, resourceName); + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param graph the graph containing the standard ModeShape CND content + * @param parentOfTypes the path to the parent of the node type definition nodes + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @Override + public void read( Graph graph, + Path parentOfTypes, + String resourceName ) { + super.read(graph, parentOfTypes, resourceName); + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param subgraph the subgraph containing the standard ModeShape CND content + * @param locationOfParent the location to the parent of the node type definition nodes + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + @Override + public void read( Subgraph subgraph, + Location locationOfParent, + String resourceName ) { + super.read(subgraph, locationOfParent, resourceName); + } + + /** + * {@inheritDoc} + * + * @see org.modeshape.jcr.GraphNodeTypeReader#importFrom(org.modeshape.graph.io.Destination, + * org.modeshape.graph.property.Path, java.lang.String, java.lang.String) + */ + @Override + protected void importFrom( Destination destination, + Path path, + String content, + String resourceName ) throws Exception { + XmlImporter importer = new XmlImporter(destination, pathFactory.createRootPath()); + importer.importFrom(content, problems, resourceName); + } + + protected static class XmlImporter { + protected final List VALID_ON_PARENT_VERSION = Collections.unmodifiableList(Arrays.asList(new String[] {"COPY", + "VERSION", "INITIALIZE", "COMPUTE", "IGNORE", "ABORT"})); + + protected final Destination destination; + protected final Path outputPath; + protected final PropertyFactory propertyFactory; + protected final PathFactory pathFactory; + protected final NameFactory nameFactory; + protected final ValueFactories valueFactories; + + /** + * Create a new importer that will place the content in the supplied destination under the supplied path. + * + * @param destination the destination where content is to be written + * @param parentPath the path in the destination below which the generated content is to appear + * @param compatibleWithPreJcr2 true if this parser should accept the CND format that was used in the reference + * implementation prior to JCR 2.0. + * @throws IllegalArgumentException if either parameter is null + */ + public XmlImporter( Destination destination, + Path parentPath, + boolean compatibleWithPreJcr2 ) { + CheckArg.isNotNull(destination, "destination"); + CheckArg.isNotNull(parentPath, "parentPath"); + this.destination = destination; + this.outputPath = parentPath; + ExecutionContext context = destination.getExecutionContext(); + this.valueFactories = context.getValueFactories(); + this.propertyFactory = context.getPropertyFactory(); + this.pathFactory = valueFactories.getPathFactory(); + this.nameFactory = valueFactories.getNameFactory(); + } + + /** + * Create a new importer that will place the content in the supplied destination under the supplied path. This parser will + * accept the Jackrabbit XML format. + * + * @param destination the destination where content is to be written + * @param parentPath the path in the destination below which the generated content is to appear + * @throws IllegalArgumentException if either parameter is null + */ + public XmlImporter( Destination destination, + Path parentPath ) { + this(destination, parentPath, true); + } + + /** + * Import the CND content from the supplied stream, placing the content into the importer's destination. + * + * @param stream the stream containing the CND content + * @param problems where any problems encountered during import should be reported + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + * @throws IOException if there is a problem reading from the supplied stream + * @throws SAXException if there is an error in the XML + */ + @SuppressWarnings( "cast" ) + public void importFrom( InputStream stream, + Problems problems, + String resourceName ) throws SAXException, IOException { + try { + parse(stream, problems, resourceName); + destination.submit(); + } catch (RuntimeException e) { + problems.addError(e, JcrI18n.errorImportingNodeTypeContent, (Object)resourceName, e.getMessage()); + } + } + + /** + * Import the CND content from the supplied stream, placing the content into the importer's destination. + * + * @param file the file containing the CND content + * @param problems where any problems encountered during import should be reported + * @throws IOException if there is a problem reading from the supplied file + * @throws SAXException if there is an error in the XML + */ + public void importFrom( File file, + Problems problems ) throws SAXException, IOException { + importFrom(IoUtil.read(file), problems, file.getCanonicalPath()); + } + + /** + * Import the CND content from the supplied stream, placing the content into the importer's destination. + * + * @param content the string containing the CND content + * @param problems where any problems encountered during import should be reported + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + * @throws IOException if there is a problem reading from the supplied string + * @throws SAXException if there is an error in the XML + */ + public void importFrom( String content, + Problems problems, + String resourceName ) throws SAXException, IOException { + importFrom(new ByteArrayInputStream(content.getBytes()), problems, resourceName); + } + + /** + * Parse the XML content. + * + * @param content the content + * @param problems where any problems encountered during import should be reported + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + * @throws IOException if there is a problem reading from the supplied stream + * @throws SAXException if there is an error in the XML + */ + @SuppressWarnings( "cast" ) + protected void parse( InputStream content, + Problems problems, + String resourceName ) throws SAXException, IOException { + ExecutionContext context = destination.getExecutionContext(); + InMemoryRepositorySource source = new InMemoryRepositorySource(); + source.setName("XML Import Source"); + Graph graph = Graph.create(source, context); + graph.importXmlFrom(content).into("/"); + + // Now read the graph and convert it into our format ... + try { + Subgraph subgraph = graph.getSubgraphOfDepth(5).at("/nodeTypes"); + Path path = outputPath; + for (Location location : subgraph.getRoot().getChildren()) { + SubgraphNode nodeType = subgraph.getNode(location); + parseNodeType(subgraph, nodeType, path); + } + } catch (PathNotFoundException e) { + problems.addError(e, JcrI18n.nodeTypesNotFoundInXml, (Object)resourceName, e.getMessage()); + } + } + + /** + * Parse the node type element. + * + *
+         *     <!ELEMENT nodeType (supertypes?|propertyDefinition*|childNodeDefinition*)>
+         *     <!ATTLIST nodeType
+         *             name CDATA #REQUIRED
+         *             isMixin (true|false) #REQUIRED
+         *              hasOrderableChildNodes (true|false) #REQUIRED
+         *             primaryItemName CDATA #REQUIRED
+         *         >
+         *     <!ELEMENT supertypes (supertype+)>
+         *     <!ELEMENT supertype (CDATA)>
+         * 
+ * + * @param subgraph + * @param nodeType + * @param parentPath + */ + protected void parseNodeType( Subgraph subgraph, + SubgraphNode nodeType, + Path parentPath ) { + // Parse the name, and create the path and a property for the name ... + Name name = readName(nodeType, "name", null); + Path nodeTypePath = pathFactory.create(parentPath, name); + List properties = new ArrayList(); + properties.add(propertyFactory.create(JcrLexicon.NODE_TYPE_NAME, name)); + + // Read the node type options ... + boolean isOrderable = readBoolean(nodeType, "hasOrderableChildNodes", false); + boolean isMixin = readBoolean(nodeType, "isMixin", false); + boolean isAbstract = readBoolean(nodeType, "isAbstract", false); + boolean isQueryable = readBoolean(nodeType, "isQueryable", true); + String onParentVersion = "COPY"; + Name primaryItemName = readName(nodeType, "primaryItemName", null); + properties.add(propertyFactory.create(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, isOrderable)); + properties.add(propertyFactory.create(JcrLexicon.IS_MIXIN, isMixin)); + properties.add(propertyFactory.create(JcrLexicon.IS_ABSTRACT, isAbstract)); + properties.add(propertyFactory.create(JcrLexicon.IS_QUERYABLE, isQueryable)); + properties.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion.toUpperCase())); + if (primaryItemName != null) { + properties.add(propertyFactory.create(JcrLexicon.PRIMARY_ITEM_NAME, primaryItemName)); + } + + SubgraphNode supertypes = nodeType.getNode(name("supertypes")); + if (supertypes != null) { + // Read the supertypes, which are imported as a "supertype" multi-valued property ... + List supertypeNames = readNames(supertypes, "supertype", JcrNtLexicon.BASE); + properties.add(propertyFactory.create(JcrLexicon.SUPERTYPES, supertypeNames)); // even if empty + } + destination.create(nodeTypePath, properties); + + for (Location childLocation : nodeType.getChildren()) { + SubgraphNode child = subgraph.getNode(childLocation); + Name childName = nameFrom(child); + if (childName.getLocalName().equals("propertyDefinition")) { + parsePropertyDefinition(subgraph, child, nodeTypePath); + } else if (childName.getLocalName().equals("childNodeDefinition")) { + parseChildNodeDefinition(subgraph, child, nodeTypePath); + } + } + } + + /** + * Read the property definition from the graph and create the corresponding CND content in the destination. + * + *
+         *  <!ELEMENT propertyDefinition (valueConstraints?|defaultValues?)>
+         *     <!ATTLIST propertyDefinition
+         *             name CDATA #REQUIRED
+         *             requiredType (String|Date|Path|Name|Reference|Binary|Double|Long|Boolean|undefined) #REQUIRED
+         *             autoCreated (true|false) #REQUIRED
+         *             mandatory (true|false) #REQUIRED
+         *             onParentVersion (COPY|VERSION|INITIALIZE|COMPUTE|IGNORE|ABORT) #REQUIRED
+         *             protected (true|false) #REQUIRED
+         *             multiple  (true|false) #REQUIRED
+         *         >
+         *     <!ELEMENT valueConstraints (valueConstraint+)>
+         *     <!ELEMENT valueConstraint (CDATA)>
+         *     <!ELEMENT defaultValues (defaultValue+)>
+         *     <!ELEMENT defaultValue (CDATA)>
+         * 
+ * + * @param subgraph + * @param propertyDefn + * @param parentPath + */ + protected void parsePropertyDefinition( Subgraph subgraph, + SubgraphNode propertyDefn, + Path parentPath ) { + // Parse the name, and create the path and a property for the name ... + Name name = readName(propertyDefn, "name", null); + Path nodeTypePath = pathFactory.create(parentPath, JcrLexicon.PROPERTY_DEFINITION); + List properties = new ArrayList(); + properties.add(propertyFactory.create(JcrLexicon.NAME, name)); + + // Read the node type options ... + boolean autoCreated = readBoolean(propertyDefn, "autoCreated", false); + boolean mandatory = readBoolean(propertyDefn, "mandatory", false); + boolean multiple = readBoolean(propertyDefn, "multiple", false); + boolean isProtected = readBoolean(propertyDefn, "protected", false); + boolean isFullTextSearchable = readBoolean(propertyDefn, "fullTextSearchable", true); + boolean isQueryOrderable = true; + String onParentVersion = readString(propertyDefn, "onParentVersion", "COPY"); + String requiredType = readString(propertyDefn, "requiredType", "UNDEFINED"); + + properties.add(propertyFactory.create(JcrLexicon.AUTO_CREATED, autoCreated)); + properties.add(propertyFactory.create(JcrLexicon.MANDATORY, mandatory)); + properties.add(propertyFactory.create(JcrLexicon.PROTECTED, isProtected)); + properties.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion.toUpperCase())); + properties.add(propertyFactory.create(JcrLexicon.MULTIPLE, multiple)); + properties.add(propertyFactory.create(JcrLexicon.IS_FULL_TEXT_SEARCHABLE, isFullTextSearchable)); + properties.add(propertyFactory.create(JcrLexicon.IS_QUERY_ORDERABLE, isQueryOrderable)); + properties.add(propertyFactory.create(JcrLexicon.REQUIRED_TYPE, requiredType.toUpperCase())); + + for (Location childLocation : propertyDefn.getChildren()) { + SubgraphNode child = subgraph.getNode(childLocation); + Name childName = nameFrom(child); + if (childName.getLocalName().equals("valueConstraints")) { + // Read the supertypes, which are imported as a "valueConstraint" multi-valued property ... + List valueConstraints = readStrings(child, "valueConstraint"); + if (valueConstraints != null && !valueConstraints.isEmpty()) { + properties.add(propertyFactory.create(JcrLexicon.VALUE_CONSTRAINTS, valueConstraints)); + } + } else if (childName.getLocalName().equals("defaultValues")) { + // Read the supertypes, which are imported as a "valueConstraint" multi-valued property ... + List defaultValues = readStrings(child, "defaultValue"); + if (defaultValues != null && !defaultValues.isEmpty()) { + properties.add(propertyFactory.create(JcrLexicon.DEFAULT_VALUES, defaultValues)); + } + } + } + + destination.create(nodeTypePath, properties); + } + + /** + * Read the property definition from the graph and create the corresponding CND content in the destination. + * + *
+         *     <!ELEMENT childNodeDefinition (requiredPrimaryTypes)>
+         *     <!ATTLIST childNodeDefinition
+         *             name CDATA #REQUIRED
+         *             defaultPrimaryType  CDATA #REQUIRED
+         *             autoCreated (true|false) #REQUIRED
+         *             mandatory (true|false) #REQUIRED
+         *             onParentVersion (COPY|VERSION|INITIALIZE|COMPUTE|IGNORE|ABORT) #REQUIRED
+         *             protected (true|false) #REQUIRED
+         *             sameNameSiblings (true|false) #REQUIRED
+         *         >
+         *     <!ELEMENT requiredPrimaryTypes (requiredPrimaryType+)>
+         *     <!ELEMENT requiredPrimaryType (CDATA)>
+         * 
+ * + * @param subgraph + * @param childDefn + * @param parentPath + */ + protected void parseChildNodeDefinition( Subgraph subgraph, + SubgraphNode childDefn, + Path parentPath ) { + // Parse the name, and create the path and a property for the name ... + Name name = readName(childDefn, "name", null); + Path nodeTypePath = pathFactory.create(parentPath, JcrLexicon.CHILD_NODE_DEFINITION); + List properties = new ArrayList(); + properties.add(propertyFactory.create(JcrLexicon.NAME, name)); + + // Read the node type options ... + boolean autoCreated = readBoolean(childDefn, "autoCreated", false); + boolean mandatory = readBoolean(childDefn, "mandatory", false); + String onParentVersion = readString(childDefn, "onParentVersion", "COPY"); + boolean isProtected = readBoolean(childDefn, "protected", false); + boolean sns = readBoolean(childDefn, "sameNameSiblings", false); + Name defaultPrimaryType = readName(childDefn, "defaultPrimaryType", null); + + properties.add(propertyFactory.create(JcrLexicon.AUTO_CREATED, autoCreated)); + properties.add(propertyFactory.create(JcrLexicon.MANDATORY, mandatory)); + properties.add(propertyFactory.create(JcrLexicon.PROTECTED, isProtected)); + properties.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion.toUpperCase())); + properties.add(propertyFactory.create(JcrLexicon.SAME_NAME_SIBLINGS, sns)); + if (defaultPrimaryType != null) { + properties.add(propertyFactory.create(JcrLexicon.DEFAULT_PRIMARY_TYPE, defaultPrimaryType)); + } + + for (Location childLocation : childDefn.getChildren()) { + SubgraphNode child = subgraph.getNode(childLocation); + Name childName = nameFrom(child); + if (childName.getLocalName().equals("requiredPrimaryTypes")) { + // Read the supertypes, which are imported as a "valueConstraint" multi-valued property ... + List requiredPrimaryTypes = readNames(child, "requiredPrimaryType", JcrNtLexicon.BASE); + if (requiredPrimaryTypes != null && !requiredPrimaryTypes.isEmpty()) { + properties.add(propertyFactory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, requiredPrimaryTypes)); + } + } + } + + destination.create(nodeTypePath, properties); + } + + protected Name nameFrom( SubgraphNode node ) { + return node.getLocation().getPath().getLastSegment().getName(); + } + + protected Name name( String name ) { + return nameFactory.create(name); + } + + protected boolean readBoolean( SubgraphNode node, + String propertyName, + boolean defaultValue ) { + Property property = node.getProperty(propertyName); + return property != null ? valueFactories.getBooleanFactory().create(property.getFirstValue()) : defaultValue; + } + + protected String readString( SubgraphNode node, + String propertyName, + String defaultValue ) { + Property property = node.getProperty(propertyName); + return property != null ? valueFactories.getStringFactory().create(property.getFirstValue()) : defaultValue; + } + + protected List readStrings( SubgraphNode node, + String propertyName ) { + List results = new ArrayList(); + Property property = node.getProperty(propertyName); + if (property != null) { + for (Object value : property) { + String str = valueFactories.getStringFactory().create(value); + if (str != null && str.length() != 0) results.add(str); + } + } + return results; + } + + protected Name readName( SubgraphNode node, + String propertyName, + Name defaultValue ) { + Property property = node.getProperty(propertyName); + if (property != null && !property.isEmpty()) { + String firstValue = valueFactories.getStringFactory().create(property.getFirstValue()); + if (firstValue != null && firstValue.trim().length() != 0) { + return valueFactories.getNameFactory().create(firstValue); + } + } + return defaultValue; + } + + protected List readNames( SubgraphNode node, + String propertyName, + Name defaultIfNone ) { + List results = new ArrayList(); + Property property = node.getProperty(propertyName); + if (property != null) { + for (Object value : property) { + Name name = valueFactories.getNameFactory().create(value); + if (name != null) results.add(name); + } + } + if (results.isEmpty() && defaultIfNone != null) results.add(defaultIfNone); + return results; + } + } + +} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (working copy) @@ -119,6 +119,8 @@ public final class JcrI18n { public static I18n typeNotFound; public static I18n supertypeNotFound; + public static I18n errorImportingNodeTypeContent; + public static I18n nodeTypesNotFoundInXml; public static I18n systemSourceNameOptionValueDoesNotReferenceExistingSource; public static I18n systemSourceNameOptionValueDoesNotReferenceValidWorkspace; Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrItemDefinitionTemplate.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrItemDefinitionTemplate.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrItemDefinitionTemplate.java (working copy) @@ -30,7 +30,10 @@ import javax.jcr.version.OnParentVersionAction; import net.jcip.annotations.NotThreadSafe; import org.modeshape.graph.ExecutionContext; import org.modeshape.graph.property.Name; +import org.modeshape.graph.property.NamespaceRegistry; +import org.modeshape.graph.property.Path; import org.modeshape.graph.property.ValueFormatException; +import org.modeshape.graph.property.Path.Segment; /** * ModeShape convenience implementation to support the JCR 2 NodeDefinitionTemplate and PropertyDefinitionTemplate classes. @@ -38,6 +41,31 @@ import org.modeshape.graph.property.ValueFormatException; @NotThreadSafe abstract class JcrItemDefinitionTemplate implements ItemDefinition { + protected static void registerMissingNamespaces( ExecutionContext originalContext, + ExecutionContext newContext, + Path path ) { + for (Segment segment : path) { + registerMissingNamespaces(originalContext, newContext, segment.getName()); + } + } + + protected static void registerMissingNamespaces( ExecutionContext originalContext, + ExecutionContext newContext, + Name... names ) { + if (names == null) return; + NamespaceRegistry newRegistry = newContext.getNamespaceRegistry(); + NamespaceRegistry originalRegistry = originalContext.getNamespaceRegistry(); + for (Name name : names) { + if (name != null) { + String uri = name.getNamespaceUri(); + if (!newRegistry.isRegisteredNamespaceUri(uri)) { + String prefix = originalRegistry.getPrefixForNamespaceUri(uri, false); + newRegistry.register(prefix, uri); + } + } + } + } + private final ExecutionContext context; private boolean autoCreated = false; private boolean mandatory = false; @@ -51,6 +79,17 @@ abstract class JcrItemDefinitionTemplate implements ItemDefinition { this.context = context; } + JcrItemDefinitionTemplate( JcrItemDefinitionTemplate original, + ExecutionContext context ) { + this.context = context; + this.autoCreated = original.autoCreated; + this.mandatory = original.mandatory; + this.isProtected = original.isProtected; + this.name = original.name; + this.onParentVersion = original.onParentVersion; + JcrItemDefinitionTemplate.registerMissingNamespaces(original.context, context, this.name); + } + ExecutionContext getExecutionContext() { return context; } Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeDefinitionTemplate.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeDefinitionTemplate.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeDefinitionTemplate.java (working copy) @@ -47,6 +47,20 @@ class JcrNodeDefinitionTemplate extends JcrItemDefinitionTemplate implements Nod super(context); } + JcrNodeDefinitionTemplate( JcrNodeDefinitionTemplate original, + ExecutionContext context ) { + super(original, context); + this.defaultPrimaryType = original.defaultPrimaryType; + this.requiredPrimaryTypes = original.requiredPrimaryTypes; + this.allowSameNameSiblings = original.allowSameNameSiblings; + JcrItemDefinitionTemplate.registerMissingNamespaces(original.getContext(), context, this.defaultPrimaryType); + JcrItemDefinitionTemplate.registerMissingNamespaces(original.getContext(), context, this.requiredPrimaryTypes); + } + + JcrNodeDefinitionTemplate with( ExecutionContext context ) { + return context == super.getContext() ? this : new JcrNodeDefinitionTemplate(this, context); + } + /** * {@inheritDoc} *

Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeManager.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeManager.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeManager.java (working copy) @@ -430,7 +430,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { *

* * @param template the new node type to register - * @param allowUpdate must be {@code false}; ModeShape does not allow updating node types at this time + * @param allowUpdate this flag is not used * @return the {@code newly created node type} * @throws InvalidNodeTypeDefinitionException if the {@code NodeTypeDefinition} is invalid * @throws NodeTypeExistsException if {@code allowUpdate} is false and the {@code NodeTypeDefinition} specifies a node type @@ -453,7 +453,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { throw new AccessDeniedException(ace); } try { - return this.repositoryTypeManager.registerNodeType(template, allowUpdate); + return this.repositoryTypeManager.registerNodeType(template); } finally { schemata = null; } @@ -467,7 +467,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { *

* * @param templates the new node types to register - * @param allowUpdates must be {@code false}; ModeShape does not allow updating node types at this time + * @param allowUpdates this flag is not used * @return the {@code newly created node types} * @throws InvalidNodeTypeDefinitionException if a {@code NodeTypeDefinition} within the collection is invalid * @throws NodeTypeExistsException if {@code allowUpdate} is false and a {@code NodeTypeDefinition} within the collection @@ -490,7 +490,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { throw new AccessDeniedException(ace); } try { - return new JcrNodeTypeIterator(repositoryTypeManager.registerNodeTypes(templates, allowUpdates)); + return new JcrNodeTypeIterator(repositoryTypeManager.registerNodeTypes(templates)); } finally { schemata = null; } @@ -503,7 +503,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { * The effect of the method is "all or nothing"; if an error occurs, no node types are registered or updated. *

* - * @param source the new node types to register + * @param nodeTypes the iterable object containing the new node types to register * @return the {@code newly created node types} * @throws InvalidNodeTypeDefinitionException if a {@code NodeTypeDefinition} within the collection is invalid * @throws NodeTypeExistsException if {@code allowUpdate} is false and a {@code NodeTypeDefinition} within the collection @@ -514,7 +514,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { * type permission}. * @throws RepositoryException if another error occurs */ - public NodeTypeIterator registerNodeTypes( JcrNodeTypeSource source ) + public NodeTypeIterator registerNodeTypes( Iterable nodeTypes ) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException { @@ -525,7 +525,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { } try { - return new JcrNodeTypeIterator(this.repositoryTypeManager.registerNodeTypes(source)); + return new JcrNodeTypeIterator(this.repositoryTypeManager.registerNodeTypes(nodeTypes)); } finally { schemata = null; } @@ -562,7 +562,7 @@ public class JcrNodeTypeManager implements NodeTypeManager { } try { - return new JcrNodeTypeIterator(this.repositoryTypeManager.registerNodeTypes(Arrays.asList(ntds), allowUpdate)); + return new JcrNodeTypeIterator(this.repositoryTypeManager.registerNodeTypes(ntds)); } finally { schemata = null; } Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeSource.java deleted file mode 100644 =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeSource.java (revision 2037) +++ /dev/null (working copy) @@ -1,57 +0,0 @@ -package org.modeshape.jcr; - -import javax.jcr.nodetype.NodeType; -import org.modeshape.graph.Graph; - -/** - * Interface for any potential provider of {@link JcrNodeType} definitions, the ModeShape implementation of {@link NodeType}. Possible - * sources of node type definitions include CND files, repository metadata, and mock types for testing. - * - * @see JcrWorkspace#getNodeTypeManager() - */ -public interface JcrNodeTypeSource { - - /** - * Returns the node type information to be registered in graph form. The graph has a very specific required format. - *

- * The root node of the graph should have zero or more children. Each child of the root node represents a type to be - * registered and the name of the node should be the name of the node type to be registered. Additionally, any facets of the - * node type that are specified should be set in a manner consistent with the JCR specification for the {@code nt:nodeType} - * built-in node type. The {@code jcr:primaryType} property does not need to be set on these nodes, but the nodes must be - * semantically valid as if the {@code jcr:primaryType} property was set. - *

- *

- * Each node type node may have zero or more children, each with the name {@code jcr:propertyDefinition} or {@code - * jcr:childNodeDefinition}, as per the definition of the {@code nt:nodeType} built-in type. Each property definition and - * child node definition must obey the semantics of {@code jcr:propertyDefinition} and {@code jcr:childNodeDefinition} - * respectively However these nodes also do not need to have the {@code jcr:primaryType} property set. - *

- *

- * For example, one valid graph is: - * - *

-     * <root>
-     * +---- test:testMixinType
-     *        +--- jcr:nodeTypeName               =  test:testMixinType  (PROPERTY)
-     *        +--- jcr:isMixin                    =  true                (PROPERTY)    
-     *        +--- jcr:childNodeDefinition                               (CHILD NODE)
-     *        |     +--- jcr:name                 =  test:childNodeA     (PROPERTY)
-     *        |     +--- jcr:mandatory            =  true                (PROPERTY)
-     *        |     +--- jcr:autoCreated          =  true                (PROPERTY)
-     *        |     +--- jcr:defaultPrimaryType   =  nt:base             (PROPERTY)
-     *        |     +--- jcr:requiredPrimaryTypes =  nt:base             (PROPERTY)
-     *        +--- jcr:propertyDefinition                                (CHILD NODE)
-     *              +--- jcr:name                 =  test:propertyA      (PROPERTY)
-     *              +--- jcr:multiple             =  true                (PROPERTY)
-     *              +--- jcr:requiredType         =  String              (PROPERTY)
-     * 
- * - * This graph (when registered) would create a mixin node named "test:testMixinType" with a mandatory, autocreated child node - * named "test:childNodeA" with a default and required primary type of "nt:base" and a multi-valued string property named - * "test:propertyA". - *

- * - * @return a graph with the semantics noted above - */ - Graph getNodeTypes(); -} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeTemplate.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeTemplate.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeTemplate.java (working copy) @@ -68,6 +68,32 @@ public class JcrNodeTypeTemplate implements NodeTypeDefinition, NodeTypeTemplate this.createdFromExistingDefinition = createdFromExistingDefinition; } + JcrNodeTypeTemplate( JcrNodeTypeTemplate original, + ExecutionContext context ) { + this.context = context; + this.isAbstract = original.isAbstract; + this.queryable = original.queryable; + this.mixin = original.mixin; + this.name = original.name; + this.orderableChildNodes = original.orderableChildNodes; + this.declaredSupertypeNames = original.declaredSupertypeNames; + this.primaryItemName = original.primaryItemName; + JcrItemDefinitionTemplate.registerMissingNamespaces(original.context, context, this.name); + JcrItemDefinitionTemplate.registerMissingNamespaces(original.context, context, this.declaredSupertypeNames); + JcrItemDefinitionTemplate.registerMissingNamespaces(original.context, context, this.primaryItemName); + for (NodeDefinitionTemplate childDefn : original.nodeDefinitionTemplates) { + this.nodeDefinitionTemplates.add(((JcrNodeDefinitionTemplate)childDefn).with(context)); + } + for (PropertyDefinitionTemplate propDefn : original.propertyDefinitionTemplates) { + this.propertyDefinitionTemplates.add(((JcrPropertyDefinitionTemplate)propDefn).with(context)); + } + this.createdFromExistingDefinition = original.createdFromExistingDefinition; + } + + JcrNodeTypeTemplate with( ExecutionContext context ) { + return context == this.context ? this : new JcrNodeTypeTemplate(this, context); + } + ExecutionContext getExecutionContext() { return context; } Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrPropertyDefinition.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrPropertyDefinition.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrPropertyDefinition.java (working copy) @@ -87,7 +87,7 @@ class JcrPropertyDefinition extends JcrItemDefinition implements PropertyDefinit this.fullTextSearchable = fullTextSearchable; this.queryOrderable = queryOrderable; this.queryOperators = queryOperators; - this.isPrivate = name.getNamespaceUri().equals(ModeShapeIntLexicon.Namespace.URI); + this.isPrivate = name != null && ModeShapeIntLexicon.Namespace.URI.equals(name.getNamespaceUri()); } /** Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrPropertyDefinitionTemplate.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrPropertyDefinitionTemplate.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrPropertyDefinitionTemplate.java (working copy) @@ -27,6 +27,8 @@ import javax.jcr.PropertyType; import javax.jcr.Value; import javax.jcr.nodetype.ConstraintViolationException; import org.modeshape.graph.ExecutionContext; +import org.modeshape.graph.property.Name; +import org.modeshape.graph.property.Path; import org.modeshape.graph.property.ValueFactories; import org.modeshape.jcr.nodetype.PropertyDefinitionTemplate; @@ -47,6 +49,41 @@ class JcrPropertyDefinitionTemplate extends JcrItemDefinitionTemplate implements super(context); } + JcrPropertyDefinitionTemplate( JcrPropertyDefinitionTemplate original, + ExecutionContext context ) { + super(original, context); + this.multiple = original.multiple; + this.requiredType = original.requiredType; + this.valueConstraints = original.valueConstraints; + this.fullTextSearchable = original.fullTextSearchable; + this.queryOrderable = original.queryOrderable; + this.availableQueryOperators = original.availableQueryOperators; + this.defaultValues = original.defaultValues != null ? new Value[original.defaultValues.length] : null; + if (original.defaultValues != null) { + for (int i = 0; i != original.defaultValues.length; ++i) { + Value originalValue = original.defaultValues[i]; + assert originalValue instanceof JcrValue; + JcrValue jcrValue = ((JcrValue)originalValue); + SessionCache cache = jcrValue.sessionCache(); + this.defaultValues[i] = new JcrValue(context.getValueFactories(), cache, jcrValue.getType(), jcrValue.value()); + switch (jcrValue.getType()) { + case PropertyType.NAME: + Name nameValue = original.getContext().getValueFactories().getNameFactory().create(jcrValue.value()); + JcrItemDefinitionTemplate.registerMissingNamespaces(original.getContext(), context, nameValue); + break; + case PropertyType.PATH: + Path pathValue = original.getContext().getValueFactories().getPathFactory().create(jcrValue.value()); + JcrItemDefinitionTemplate.registerMissingNamespaces(original.getContext(), context, pathValue); + break; + } + } + } + } + + JcrPropertyDefinitionTemplate with( ExecutionContext context ) { + return context == super.getContext() ? this : new JcrPropertyDefinitionTemplate(this, context); + } + /** * {@inheritDoc} * Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (working copy) @@ -561,8 +561,9 @@ public class JcrRepository implements Repository { boolean includeInheritedProperties = Boolean.valueOf(this.options.get(Option.TABLES_INCLUDE_COLUMNS_FOR_INHERITED_PROPERTIES)); // this.repositoryTypeManager = new RepositoryNodeTypeManager(this, includeInheritedProperties); this.repositoryTypeManager = new RepositoryNodeTypeManager(this, includeInheritedProperties); - this.repositoryTypeManager.registerNodeTypes(new CndNodeTypeSource(new String[] { - "/org/modeshape/jcr/jsr_283_builtins.cnd", "/org/modeshape/jcr/modeshape_builtins.cnd"})); + CndNodeTypeReader nodeTypeReader = new CndNodeTypeReader(this.executionContext); + nodeTypeReader.readBuiltInTypes(); + this.repositoryTypeManager.registerNodeTypes(nodeTypeReader); } catch (RepositoryException re) { re.printStackTrace(); throw new IllegalStateException("Could not load node type definition files", re); Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrValue.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrValue.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrValue.java (working copy) @@ -85,6 +85,17 @@ final class JcrValue implements Value, org.modeshape.jcr.api.Value { this.value = value instanceof JcrBinary ? ((JcrBinary)value).binary() : value; } + JcrValue( ValueFactories valueFactories, + SessionCache sessionCache, + Value value ) throws RepositoryException { + assert value != null; + + this.valueFactories = valueFactories; + this.sessionCache = sessionCache; + this.type = value.getType(); + this.value = valueToType(this.type, value); + } + private ValueFormatException createValueFormatException( Class type ) { return new ValueFormatException(JcrI18n.cannotConvertValue.text(value.getClass().getSimpleName(), type.getSimpleName())); } @@ -484,6 +495,42 @@ final class JcrValue implements Value, org.modeshape.jcr.api.Value { } } + protected Object valueToType( int type, + Value value ) throws RepositoryException { + switch (type) { + case PropertyType.BOOLEAN: + return valueFactories.getBooleanFactory().create(value.getBoolean()); + case PropertyType.DATE: + return valueFactories.getDateFactory().create(value.getDate()); + case PropertyType.NAME: + return valueFactories.getNameFactory().create(value.getString()); + case PropertyType.PATH: + return valueFactories.getPathFactory().create(value.getString()); + case PropertyType.REFERENCE: + case PropertyType.WEAKREFERENCE: + return valueFactories.getReferenceFactory().create(value.getString()); + case PropertyType.DOUBLE: + return valueFactories.getDoubleFactory().create(value.getDouble()); + case PropertyType.LONG: + return valueFactories.getLongFactory().create(value.getLong()); + case PropertyType.DECIMAL: + return valueFactories.getDecimalFactory().create(value.getDecimal()); + case PropertyType.URI: + return valueFactories.getUriFactory().create(value.getString()); + case PropertyType.BINARY: + return valueFactories.getBinaryFactory().create(value.getBinary()); + case PropertyType.STRING: + return valueFactories.getStringFactory().create(value.getString()); + case PropertyType.UNDEFINED: + return value.getString(); + + default: + assert false : "Unexpected JCR property type " + type; + // This should still throw an exception even if assertions are turned off + throw new IllegalStateException("Invalid property type " + type); + } + } + @Override public String toString() { return (value == null ? "null" : value.toString()) + " (" + PropertyType.nameFromValue(type) + ")"; Index: modeshape-jcr/src/main/java/org/modeshape/jcr/NodeTemplateNodeTypeSource.java deleted file mode 100644 =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/NodeTemplateNodeTypeSource.java (revision 2037) +++ /dev/null (working copy) @@ -1,302 +0,0 @@ -/* - * ModeShape (http://www.modeshape.org) - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. Some portions may be licensed - * to Red Hat, Inc. under one or more contributor license agreements. - * See the AUTHORS.txt file in the distribution for a full listing of - * individual contributors. - * - * ModeShape is free software. Unless otherwise indicated, all code in ModeShape - * is licensed to you under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * ModeShape is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.modeshape.jcr; - -import java.util.Arrays; -import java.util.List; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; -import javax.jcr.Value; -import javax.jcr.nodetype.NodeDefinition; -import javax.jcr.nodetype.NodeTypeTemplate; -import javax.jcr.nodetype.PropertyDefinition; -import javax.jcr.version.OnParentVersionAction; -import net.jcip.annotations.NotThreadSafe; -import org.modeshape.graph.ExecutionContext; -import org.modeshape.graph.Graph; -import org.modeshape.graph.JcrLexicon; -import org.modeshape.graph.JcrNtLexicon; -import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; -import org.modeshape.graph.io.Destination; -import org.modeshape.graph.io.GraphBatchDestination; -import org.modeshape.graph.property.Name; -import org.modeshape.graph.property.NameFactory; -import org.modeshape.graph.property.Path; -import org.modeshape.graph.property.PathFactory; -import org.modeshape.graph.property.PropertyFactory; -import org.modeshape.graph.property.ValueFactory; -import org.modeshape.jcr.nodetype.InvalidNodeTypeDefinitionException; - -/** - * Class to convert one or more {@link NodeTypeTemplate node type templates} containing custom node type definitions into a format - * that can be registered with the {@link JcrNodeTypeManager}. - *

- * As the JSR-283 specification mandates that node type templates be the standard basis for custom type registration, the - * {@link RepositoryNodeTypeManager#registerNodeTypes(java.util.Collection, boolean)} method should be used in preference to - * manually instantiating this class. - *

- */ -@NotThreadSafe -class NodeTemplateNodeTypeSource implements JcrNodeTypeSource { - - private final Graph graph; - private final PathFactory pathFactory; - private final NameFactory nameFactory; - private final ValueFactory booleanFactory; - private final ValueFactory stringFactory; - private final Destination destination; - - public NodeTemplateNodeTypeSource( NodeTypeTemplate nodeTypeTemplate ) throws InvalidNodeTypeDefinitionException { - this(Arrays.asList(new NodeTypeTemplate[] {nodeTypeTemplate})); - } - - public NodeTemplateNodeTypeSource( List nodeTypeTemplates ) throws InvalidNodeTypeDefinitionException { - - ExecutionContext context = null; - - if (nodeTypeTemplates.isEmpty()) { - context = new ExecutionContext(); - } else { - for (NodeTypeTemplate ntt : nodeTypeTemplates) { - if (!(ntt instanceof JcrNodeTypeTemplate)) { - throw new IllegalArgumentException(JcrI18n.cannotConvertValue.text(ntt.getClass(), JcrNodeTypeTemplate.class)); - } - - JcrNodeTypeTemplate jntt = (JcrNodeTypeTemplate)ntt; - if (context == null) { - context = jntt.getExecutionContext(); - assert context != null; - } else { - if (context != jntt.getExecutionContext()) { - throw new IllegalArgumentException(JcrI18n.allNodeTypeTemplatesMustComeFromSameSession.text()); - } - } - } - } - - assert context != null; - this.pathFactory = context.getValueFactories().getPathFactory(); - this.nameFactory = context.getValueFactories().getNameFactory(); - this.booleanFactory = context.getValueFactories().getBooleanFactory(); - this.stringFactory = context.getValueFactories().getStringFactory(); - - PathFactory pathFactory = context.getValueFactories().getPathFactory(); - InMemoryRepositorySource source = new InMemoryRepositorySource(); - source.setName("NodeTypeTemplate Import Source"); - this.graph = Graph.create(source, context); - Graph.Batch batch = graph.batch(); - destination = new GraphBatchDestination(batch); - - Path rootPath = pathFactory.createRootPath(); - for (NodeTypeTemplate template : nodeTypeTemplates) { - this.createNodeType((JcrNodeTypeTemplate)template, rootPath); - } - - destination.submit(); - } - - /** - * {@inheritDoc} - * - * @see org.modeshape.jcr.JcrNodeTypeSource#getNodeTypes() - */ - public final Graph getNodeTypes() { - return graph; - } - - private boolean booleanFrom( Object value, - boolean defaultValue ) { - if (value == null) return defaultValue; - - return booleanFactory.create(value); - } - - private Name nameFrom( Object value ) { - return nameFactory.create(value); - } - - private Name[] namesFrom( Object[] values ) { - if (values == null) return new Name[0]; - - Name[] names = new Name[values.length]; - for (int i = 0; i < values.length; i++) { - names[i] = nameFactory.create(values[i]); - } - - return names; - } - - private String[] stringsFrom( Object[] values ) { - if (values == null) return new String[0]; - - String[] strings = new String[values.length]; - for (int i = 0; i < values.length; i++) { - strings[i] = stringFactory.create(values[i]); - } - - return strings; - } - - /** - * Project the custom node type definition from the given template onto the {@link #getNodeTypes() graph}. - * - * @param nodeType - * @param parentPath - * @return the path to the newly created node - * @throws InvalidNodeTypeDefinitionException - */ - protected Path createNodeType( JcrNodeTypeTemplate nodeType, - Path parentPath ) throws InvalidNodeTypeDefinitionException { - - Name name = nameFrom(nodeType.getName()); - Name[] supertypes = namesFrom(nodeType.declaredSupertypeNames()); - boolean isAbstract = booleanFrom(nodeType.isAbstract(), false); - boolean hasOrderableChildNodes = booleanFrom(nodeType.hasOrderableChildNodes(), false); - boolean isMixin = booleanFrom(nodeType.isMixin(), false); - boolean isQueryable = true; - Name primaryItemName = nameFrom(nodeType.getPrimaryItemName()); - - // Create the node for the node type ... - if (name == null) throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidNodeTypeName.text()); - Path path = pathFactory.create(parentPath, name); - - PropertyFactory factory = nodeType.getExecutionContext().getPropertyFactory(); - destination.create(path, - factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.NODE_TYPE), - factory.create(JcrLexicon.SUPERTYPES, (Object[])supertypes), - factory.create(JcrLexicon.IS_ABSTRACT, isAbstract), - factory.create(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, hasOrderableChildNodes), - factory.create(JcrLexicon.IS_MIXIN, isMixin), - factory.create(JcrLexicon.IS_QUERYABLE, isQueryable), - factory.create(JcrLexicon.NODE_TYPE_NAME, name), - factory.create(JcrLexicon.PRIMARY_ITEM_NAME, primaryItemName)); - - for (PropertyDefinition propDefn : nodeType.getPropertyDefinitionTemplates()) { - createPropertyDefinition((JcrPropertyDefinitionTemplate)propDefn, path); - } - - for (NodeDefinition nodeDefn : nodeType.getNodeDefinitionTemplates()) { - createChildDefinition((JcrNodeDefinitionTemplate)nodeDefn, path); - } - - return path; - } - - /** - * Project the property definition from the given template onto the {@link #getNodeTypes() graph}. - * - * @param propDefn - * @param parentPath - * @return the path to the newly created node - */ - protected Path createPropertyDefinition( JcrPropertyDefinitionTemplate propDefn, - Path parentPath ) { - Name name = nameFrom(propDefn.getName()); - String requiredType = PropertyType.nameFromValue(propDefn.getRequiredType()).toUpperCase(); - Value[] rawValues = propDefn.getDefaultValues(); - boolean multiple = booleanFrom(propDefn.isMultiple(), false); - boolean mandatory = booleanFrom(propDefn.isMandatory(), false); - boolean autoCreated = booleanFrom(propDefn.isAutoCreated(), false); - boolean isProtected = booleanFrom(propDefn.isProtected(), false); - String onParentVersion = OnParentVersionAction.nameFromValue(propDefn.getOnParentVersion()).toUpperCase(); - // /*QueryOperator[] queryOperators =*/queryOperatorsFrom(propDefn, CndLexer.QUERY_OPERATORS); - // boolean isFullTextSearchable = booleanFrom(propDefn, CndLexer.IS_FULL_TEXT_SEARCHABLE, true); - // boolean isQueryOrderable = booleanFrom(propDefn, CndLexer.IS_QUERY_ORDERERABLE, true); - String[] valueConstraints = stringsFrom(propDefn.getValueConstraints()); - - // Create the node for the node type ... - if (name == null) name = JcrNodeType.RESIDUAL_NAME; - Path path = pathFactory.create(parentPath, JcrLexicon.PROPERTY_DEFINITION); - - Object[] defaultValues; - - if (rawValues == null) { - defaultValues = new Object[0]; - } else { - try { - defaultValues = new Object[rawValues.length]; - for (int i = 0; i < rawValues.length; i++) { - defaultValues[i] = rawValues[i].getString(); - } - } catch (RepositoryException re) { - throw new IllegalStateException(re); - } - } - - PropertyFactory factory = propDefn.getExecutionContext().getPropertyFactory(); - destination.create(path, - factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.PROPERTY_DEFINITION), - factory.create(JcrLexicon.REQUIRED_TYPE, requiredType), - factory.create(JcrLexicon.DEFAULT_VALUES, defaultValues), - factory.create(JcrLexicon.MULTIPLE, multiple), - factory.create(JcrLexicon.MANDATORY, mandatory), - factory.create(JcrLexicon.NAME, name), - factory.create(JcrLexicon.AUTO_CREATED, autoCreated), - factory.create(JcrLexicon.PROTECTED, isProtected), - factory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion), - // factory.create(ModeShapeLexicon.QUERY_OPERATORS, queryOperators), - // factory.create(JcrLexicon.IS_FULL_TEXT_SEARCHABLE, isFullTextSearchable), - // factory.create(JcrLexicon.IS_QUERY_ORDERABLE, isQueryOrderable), - factory.create(JcrLexicon.VALUE_CONSTRAINTS, (Object[])valueConstraints)); - - return path; - } - - /** - * Project the child node definition from the given template onto the {@link #getNodeTypes() graph}. - * - * @param childDefn - * @param parentPath - * @return the path to the newly created node - */ - protected Path createChildDefinition( JcrNodeDefinitionTemplate childDefn, - Path parentPath ) { - Name name = nameFrom(childDefn.getName()); - Name[] requiredPrimaryTypes = namesFrom(childDefn.getRequiredPrimaryTypeNames()); - Name defaultPrimaryType = nameFrom(childDefn.getDefaultPrimaryTypeName()); - boolean mandatory = booleanFrom(childDefn.isMandatory(), false); - boolean autoCreated = booleanFrom(childDefn.isAutoCreated(), false); - boolean isProtected = booleanFrom(childDefn.isProtected(), false); - String onParentVersion = OnParentVersionAction.nameFromValue(childDefn.getOnParentVersion()).toUpperCase(); - boolean sameNameSiblings = booleanFrom(childDefn.allowsSameNameSiblings(), false); - - // Create the node for the node type ... - if (name == null) name = JcrNodeType.RESIDUAL_NAME; - Path path = pathFactory.create(parentPath, JcrLexicon.CHILD_NODE_DEFINITION); - - PropertyFactory factory = childDefn.getExecutionContext().getPropertyFactory(); - destination.create(path, - factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.CHILD_NODE_DEFINITION), - factory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, (Object[])requiredPrimaryTypes), - factory.create(JcrLexicon.DEFAULT_PRIMARY_TYPE, defaultPrimaryType), - factory.create(JcrLexicon.MANDATORY, mandatory), - factory.create(JcrLexicon.NAME, name), - factory.create(JcrLexicon.AUTO_CREATED, autoCreated), - factory.create(JcrLexicon.PROTECTED, isProtected), - factory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion), - factory.create(JcrLexicon.SAME_NAME_SIBLINGS, sameNameSiblings)); - - return path; - } -} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java (revision 2037) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java (working copy) @@ -43,7 +43,6 @@ import javax.jcr.nodetype.NoSuchNodeTypeException; import javax.jcr.nodetype.NodeDefinition; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeDefinition; -import javax.jcr.nodetype.NodeTypeTemplate; import javax.jcr.nodetype.PropertyDefinition; import javax.jcr.query.InvalidQueryException; import javax.jcr.version.OnParentVersionAction; @@ -56,18 +55,14 @@ import org.modeshape.common.util.CheckArg; import org.modeshape.graph.ExecutionContext; import org.modeshape.graph.Graph; import org.modeshape.graph.Location; -import org.modeshape.graph.Node; import org.modeshape.graph.Subgraph; import org.modeshape.graph.property.Name; import org.modeshape.graph.property.NameFactory; -import org.modeshape.graph.property.NamespaceRegistry; import org.modeshape.graph.property.Path; import org.modeshape.graph.property.PathFactory; import org.modeshape.graph.property.PathNotFoundException; import org.modeshape.graph.property.Property; import org.modeshape.graph.property.PropertyFactory; -import org.modeshape.graph.property.ValueFactories; -import org.modeshape.graph.property.ValueFactory; import org.modeshape.graph.query.QueryResults; import org.modeshape.graph.query.model.QueryCommand; import org.modeshape.graph.query.model.TypeSystem; @@ -92,28 +87,6 @@ import org.modeshape.jcr.nodetype.NodeTypeExistsException; @ThreadSafe class RepositoryNodeTypeManager { - private static final Map PROPERTY_TYPE_VALUES_FROM_NAME; - - static { - Map temp = new HashMap(); - - temp.put(PropertyType.TYPENAME_BINARY.toUpperCase(), PropertyType.BINARY); - temp.put(PropertyType.TYPENAME_BOOLEAN.toUpperCase(), PropertyType.BOOLEAN); - temp.put(PropertyType.TYPENAME_DATE.toUpperCase(), PropertyType.DATE); - temp.put(PropertyType.TYPENAME_DECIMAL.toUpperCase(), PropertyType.DECIMAL); - temp.put(PropertyType.TYPENAME_DOUBLE.toUpperCase(), PropertyType.DOUBLE); - temp.put(PropertyType.TYPENAME_LONG.toUpperCase(), PropertyType.LONG); - temp.put(PropertyType.TYPENAME_NAME.toUpperCase(), PropertyType.NAME); - temp.put(PropertyType.TYPENAME_PATH.toUpperCase(), PropertyType.PATH); - temp.put(PropertyType.TYPENAME_STRING.toUpperCase(), PropertyType.STRING); - temp.put(PropertyType.TYPENAME_REFERENCE.toUpperCase(), PropertyType.REFERENCE); - temp.put(PropertyType.TYPENAME_WEAKREFERENCE.toUpperCase(), PropertyType.WEAKREFERENCE); - temp.put(PropertyType.TYPENAME_UNDEFINED.toUpperCase(), PropertyType.UNDEFINED); - temp.put(PropertyType.TYPENAME_URI.toUpperCase(), PropertyType.URI); - - PROPERTY_TYPE_VALUES_FROM_NAME = Collections.unmodifiableMap(temp); - } - private static final TextEncoder NAME_ENCODER = new XmlNameEncoder(); private final JcrRepository repository; @@ -130,6 +103,7 @@ class RepositoryNodeTypeManager { private NodeTypeSchemata schemata; private final PropertyFactory propertyFactory; private final PathFactory pathFactory; + private final NameFactory nameFactory; private final ReadWriteLock nodeTypeManagerLock = new ReentrantReadWriteLock(); private final boolean includeColumnsForInheritedProperties; @@ -162,6 +136,7 @@ class RepositoryNodeTypeManager { this.includeColumnsForInheritedProperties = includeColumnsForInheritedProperties; this.propertyFactory = context.getPropertyFactory(); this.pathFactory = context.getValueFactories().getPathFactory(); + this.nameFactory = context.getValueFactories().getNameFactory(); propertyDefinitions = new HashMap(); childNodeDefinitions = new HashMap(); @@ -1413,27 +1388,39 @@ class RepositoryNodeTypeManager { * Registers a new node type or updates an existing node type using the specified definition and returns the resulting {@code * NodeType} object. *

- * The node type definition is wrapped in a collection and passed to the {@link #registerNodeTypes(Collection, boolean) batch - * type definition method}. + * For details, see {@link #registerNodeTypes(Iterable)}. *

* * @param ntd the {@code NodeTypeDefinition} to register - * @param allowUpdates indicates whether existing node types should be updated by the given definition * @return the newly registered (or updated) {@code NodeType} * @throws InvalidNodeTypeDefinitionException if the {@code NodeTypeDefinition} is invalid * @throws NodeTypeExistsException if allowUpdate is false and the {@code NodeTypeDefinition} specifies a node * type name that is already registered * @throws RepositoryException if another error occurs */ - JcrNodeType registerNodeType( NodeTypeDefinition ntd, - boolean allowUpdates ) + JcrNodeType registerNodeType( NodeTypeDefinition ntd ) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException { assert ntd != null; - assert ntd instanceof JcrNodeTypeTemplate; - - JcrNodeTypeTemplate jntt = (JcrNodeTypeTemplate)ntd; + List result = registerNodeTypes(Collections.singletonList(ntd)); + return result.isEmpty() ? null : result.get(0); + } - return registerNodeTypes(new NodeTemplateNodeTypeSource(jntt)).get(0); + /** + * Registers or updates the specified {@link NodeTypeDefinition} objects. + *

+ * For details, see {@link #registerNodeTypes(Iterable)}. + *

+ * + * @param ntds the node type definitions + * @return the newly registered (or updated) {@link NodeType NodeTypes} + * @throws InvalidNodeTypeDefinitionException + * @throws NodeTypeExistsException + * @throws RepositoryException + */ + List registerNodeTypes( NodeTypeDefinition[] ntds ) + throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException { + assert ntds != null; + return registerNodeTypes(Arrays.asList(ntds)); } /** @@ -1500,9 +1487,7 @@ class RepositoryNodeTypeManager { * Note that an empty set of child nodes would meet the above criteria. *

* - * @param nodeTypeBatch the batch of {@link NodeTypeDefinition node type definitions} to register - * @param allowUpdates indicates whether existing node types should be updated by the given definition; must be set to {@code - * false} in the current implementation + * @param nodeTypeDefns the {@link NodeTypeDefinition node type definitions} to register * @return the newly registered (or updated) {@link NodeType NodeTypes} * @throws UnsupportedRepositoryOperationException if {@code allowUpdates == true}. ModeShape does not support this capability * at this time but the parameter has been retained for API compatibility. @@ -1511,103 +1496,86 @@ class RepositoryNodeTypeManager { * type name that is already registered * @throws RepositoryException if another error occurs */ - List registerNodeTypes( Collection nodeTypeBatch, - boolean allowUpdates ) + List registerNodeTypes( Iterable nodeTypeDefns ) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException { - if (nodeTypeBatch.isEmpty()) { + if (nodeTypeDefns == null) { return Collections.emptyList(); } - List ntts = new ArrayList(nodeTypeBatch.size()); + List typesPendingRegistration = new ArrayList(); - for (NodeTypeDefinition ntd : nodeTypeBatch) { - assert ntd instanceof JcrNodeTypeTemplate; - ntts.add((JcrNodeTypeTemplate)ntd); - } + try { + nodeTypeManagerLock.writeLock().lock(); + for (NodeTypeDefinition nodeTypeDefn : nodeTypeDefns) { + if (nodeTypeDefn instanceof JcrNodeTypeTemplate) { + // Switch to use this context, so names are properly prefixed ... + nodeTypeDefn = ((JcrNodeTypeTemplate)nodeTypeDefn).with(context); + } + Name internalName = nameFactory.create(nodeTypeDefn.getName()); + if (internalName == null || internalName.getLocalName().length() == 0) { + throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidNodeTypeName.text()); + } - return registerNodeTypes(new NodeTemplateNodeTypeSource(ntts)); + if (nodeTypes.containsKey(internalName)) { + String name = nodeTypeDefn.getName(); + throw new NodeTypeExistsException(internalName, JcrI18n.nodeTypeAlreadyExists.text(name)); + } - } + List supertypes = supertypesFor(nodeTypeDefn, typesPendingRegistration); + JcrNodeType nodeType = nodeTypeFrom(nodeTypeDefn, supertypes); + validate(nodeType, supertypes, typesPendingRegistration); - /** - * Registers the node types from the given {@link JcrNodeTypeSource}. - *

- * The effect of this method is "all or nothing"; if an error occurs, no node types are registered or updated. - *

- *

- * ModeShape Implementation Notes - *

- *

- * ModeShape currently supports registration of batches of types with some constraints. ModeShape will allow types to be - * registered if they meet the following criteria: - *

    - *
  1. Existing types cannot be modified in-place - They must be unregistered and re-registered
  2. - *
  3. Types must have a non-null, non-empty name
  4. - *
  5. If a primary item name is specified for the node type, it must match the name of a property OR a child node, not both
  6. - *
  7. Each type must have a valid set of supertypes - that is, the type's supertypes must meet the following criteria: - *
      - *
    1. The type must have at least one supertype (unless the type is {@code nt:base}.
    2. - *
    3. No two supertypes {@code t1} and {@code t2} can declare each declare a property ({@code p1} and {@code p2}) with the - * same name and cardinality ({@code p1.isMultiple() == p2.isMultiple()}). Note that this does prohibit each {@code t1} and - * {@code t2} from having a common supertype (or super-supertype, etc.) that declares a property).
    4. - *
    5. No two supertypes {@code t1} and {@code t2} can declare each declare a child node ({@code n1} and {@code n2}) with the - * same name and SNS status ({@code p1.allowsSameNameSiblings() == p2.allowsSameNameSiblings()}). Note that this does prohibit - * each {@code t1} and {@code t2} from having a common supertype (or super-supertype, etc.) that declares a child node).
    6. - *
    - *
  8. - *
  9. Each type must have a valid set of properties - that is, the type's properties must meet the following criteria: - *
      - *
    1. Residual property definitions cannot be mandatory
    2. - *
    3. If the property is auto-created, it must specify a default value
    4. - *
    5. If the property is single-valued, it can only specify a single default value
    6. - *
    7. If the property overrides an existing property definition from a supertype, the new definition must be mandatory if the - * old definition was mandatory
    8. - *
    9. The property cannot override an existing property definition from a supertype if the ancestor definition is protected
    10. - *
    11. If the property overrides an existing property definition from a supertype that specifies value constraints, the new - * definition must have the same value constraints as the old definition. This requirement may be relaxed in a future - * version of ModeShape.
    12. - *
    13. If the property overrides an existing property definition from a supertype, the new definition must have the same - * required type as the old definition or a required type that can ALWAYS be cast to the required type of the ancestor (see - * section 3.6.4 of the JCR 2.0 specification)
    14. - *
    - * Note that an empty set of properties would meet the above criteria.
  10. - *
  11. The type must have a valid set of child nodes - that is, the types's child nodes must meet the following criteria: - *
      - *
    1. Residual child node definitions cannot be mandatory
    2. - *
    3. If the child node is auto-created, it must specify a default primary type name
    4. - *
    5. If the child node overrides an existing child node definition from a supertype, the new definition must be mandatory if - * the old definition was mandatory
    6. - *
    7. The child node cannot override an existing child node definition from a supertype if the ancestor definition is - * protected
    8. - *
    9. If the child node overrides an existing child node definition from a supertype, the required primary types of the new - * definition must be more restrictive than the required primary types of the old definition - that is, the new primary types - * must defined such that any type that satisfies all of the required primary types for the new definition must also satisfy - * all of the required primary types for the old definition. This requirement is analogous to the requirement that overriding - * property definitions have a required type that is always convertible to the required type of the overridden definition.
    10. - *
    - * Note that an empty set of child nodes would meet the above criteria.
  12. - *

    - * - * @param nodeTypeSource the batch of {@link NodeType node types} to register - * @return the newly registered (or updated) {@link NodeType NodeTypes} - * @throws UnsupportedRepositoryOperationException if {@code allowUpdates == true}. ModeShape does not support this capability - * at this time but the parameter has been retained for API compatibility. - * @throws InvalidNodeTypeDefinitionException if the {@link NodeTypeDefinition} is invalid - * @throws NodeTypeExistsException if allowUpdate is false and the {@link NodeTypeDefinition} specifies a node - * type name that is already registered - * @throws RepositoryException if another error occurs - */ - List registerNodeTypes( JcrNodeTypeSource nodeTypeSource ) - throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException { - assert nodeTypeSource != null; - Graph nodeTypesGraph = nodeTypeSource.getNodeTypes(); - Subgraph nodeTypesSubgraph = nodeTypesGraph.getSubgraphOfDepth(3).at("/"); - return registerNodeTypes(nodeTypesSubgraph, nodeTypesSubgraph.getLocation()); + typesPendingRegistration.add(nodeType); + } + + // Make sure the nodes have primary types that are either already registered, or pending registration ... + for (JcrNodeType nodeType : typesPendingRegistration) { + for (JcrNodeDefinition nodeDef : nodeType.getDeclaredChildNodeDefinitions()) { + JcrNodeType[] requiredPrimaryTypes = new JcrNodeType[nodeDef.requiredPrimaryTypeNames().length]; + int i = 0; + for (Name primaryTypeName : nodeDef.requiredPrimaryTypeNames()) { + requiredPrimaryTypes[i] = findTypeInMapOrList(primaryTypeName, typesPendingRegistration); + + if (requiredPrimaryTypes[i] == null) { + throw new RepositoryException( + JcrI18n.invalidPrimaryTypeName.text(primaryTypeName, nodeType.getName())); + } + i++; + } + } + } + + for (JcrNodeType nodeType : typesPendingRegistration) { + /* + * See comment in constructor. Using a ConcurrentHashMap seems to be to weak of a + * solution (even it were also used for childNodeDefinitions and propertyDefinitions). + * Probably need to block all read access to these maps during this phase of registration. + */ + Name name = nodeType.getInternalName(); + nodeTypes.put(name, nodeType); + for (JcrNodeDefinition childDefinition : nodeType.childNodeDefinitions()) { + childNodeDefinitions.put(childDefinition.getId(), childDefinition); + } + for (JcrPropertyDefinition propertyDefinition : nodeType.propertyDefinitions()) { + propertyDefinitions.put(propertyDefinition.getId(), propertyDefinition); + } + + // projectNodeTypeOnto(nodeType, parentOfTypeNodes, batch); + } + + // Throw away the schemata, since the node types have changed ... + this.schemata = null; + } finally { + nodeTypeManagerLock.writeLock().unlock(); + } + // batch.execute(); + + return typesPendingRegistration; } /** - * Registers the node types from the given {@link JcrNodeTypeSource}. + * Registers the node types from the given subgraph containing the node type definitions in the standard ModeShape format. *

    * The effect of this method is "all or nothing"; if an error occurs, no node types are registered or updated. *

    @@ -1680,227 +1648,87 @@ class RepositoryNodeTypeManager { throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException { assert nodeTypeSubgraph != null; assert locationOfParentOfNodeTypes != null; + CndNodeTypeReader factory = new CndNodeTypeReader(this.context); + factory.read(nodeTypeSubgraph, locationOfParentOfNodeTypes, nodeTypeSubgraph.getGraph().getSourceName()); + return registerNodeTypes(factory); + } - NamespaceRegistry namespaces = this.context.getNamespaceRegistry(); - - List nodeTypeLocations = nodeTypeSubgraph.getNode(locationOfParentOfNodeTypes).getChildren(); - List typesPendingRegistration = new ArrayList(nodeTypeLocations.size()); - - try { - nodeTypeManagerLock.writeLock().lock(); - for (Location location : nodeTypeLocations) { - Node nodeTypeNode = nodeTypeSubgraph.getNode(location); - assert location.getPath() != null; - - Name internalName = location.getPath().getLastSegment().getName(); - if (internalName == null || internalName.getLocalName().length() == 0) { - throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidNodeTypeName.text()); - } - - if (nodeTypes.containsKey(internalName)) { - throw new NodeTypeExistsException(internalName, - JcrI18n.nodeTypeAlreadyExists.text(internalName.getString(namespaces))); - } - - List supertypes = supertypesFor(nodeTypeNode, typesPendingRegistration); - // No need to re-parse the supertypes - JcrNodeType nodeType = nodeTypeFrom(nodeTypeSubgraph, location, supertypes); - - validate(nodeType, supertypes, typesPendingRegistration); - - List propertyDefs = new ArrayList( - nodeType.getDeclaredPropertyDefinitions().length); - - for (JcrPropertyDefinition propertyDef : nodeType.getDeclaredPropertyDefinitions()) { - propertyDefs.add(propertyDef.with(this.context)); - } - - List nodeDefs = new ArrayList( - nodeType.getDeclaredChildNodeDefinitions().length); - for (JcrNodeDefinition nodeDef : nodeType.getDeclaredChildNodeDefinitions()) { - nodeDefs.add(nodeDef.with(this.context).with(this)); - } - - // Create a new node type that also has the correct property and child node definitions associated - JcrNodeType newNodeType = new JcrNodeType(this.context, this, nodeType.getInternalName(), supertypes, - nodeType.getInternalPrimaryItemName(), nodeDefs, propertyDefs, - nodeType.isMixin(), nodeType.isAbstract(), nodeType.isQueryable(), - nodeType.hasOrderableChildNodes()); - typesPendingRegistration.add(newNodeType); - } - - // Make sure the nodes have primary types that are either already registered, or pending registration ... - for (JcrNodeType nodeType : typesPendingRegistration) { - for (JcrNodeDefinition nodeDef : nodeType.getDeclaredChildNodeDefinitions()) { - JcrNodeType[] requiredPrimaryTypes = new JcrNodeType[nodeDef.requiredPrimaryTypeNames().length]; - int i = 0; - for (Name primaryTypeName : nodeDef.requiredPrimaryTypeNames()) { - requiredPrimaryTypes[i] = findTypeInMapOrList(primaryTypeName, typesPendingRegistration); - - if (requiredPrimaryTypes[i] == null) { - throw new RepositoryException( - JcrI18n.invalidPrimaryTypeName.text(primaryTypeName, nodeType.getName())); - } - i++; - } - } - } - - // Graph.Batch batch = graph.batch(); - for (JcrNodeType nodeType : typesPendingRegistration) { - /* - * See comment in constructor. Using a ConcurrentHashMap seems to be to weak of a - * solution (even it were also used for childNodeDefinitions and propertyDefinitions). - * Probably need to block all read access to these maps during this phase of registration. - */ - nodeTypes.put(nodeType.getInternalName(), nodeType); - for (JcrNodeDefinition childDefinition : nodeType.childNodeDefinitions()) { - childNodeDefinitions.put(childDefinition.getId(), childDefinition); - } - for (JcrPropertyDefinition propertyDefinition : nodeType.propertyDefinitions()) { - propertyDefinitions.put(propertyDefinition.getId(), propertyDefinition); - } + private JcrNodeType nodeTypeFrom( NodeTypeDefinition nodeType, + List supertypes ) throws RepositoryException { + PropertyDefinition[] propDefns = nodeType.getDeclaredPropertyDefinitions(); + NodeDefinition[] childDefns = nodeType.getDeclaredChildNodeDefinitions(); + List properties = new ArrayList(); + List childNodes = new ArrayList(); - // projectNodeTypeOnto(nodeType, parentOfTypeNodes, batch); + if (propDefns != null) { + for (PropertyDefinition propDefn : propDefns) { + properties.add(propertyDefinitionFrom(propDefn)); } - - // Throw away the schemata, since the node types have changed ... - this.schemata = null; - } finally { - nodeTypeManagerLock.writeLock().unlock(); } - // batch.execute(); - - return typesPendingRegistration; - } - - private JcrNodeType nodeTypeFrom( Subgraph nodeTypeGraph, - Location nodeTypeLocation, - List supertypes ) { - Node nodeTypeNode = nodeTypeGraph.getNode(nodeTypeLocation); - List children = nodeTypeNode.getChildren(); - - List properties = new ArrayList(children.size()); - List childNodes = new ArrayList(children.size()); - - for (Location childLocation : children) { - if (JcrLexicon.PROPERTY_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) { - properties.add(this.propertyDefinitionFrom(nodeTypeGraph, childLocation)); - } else if (JcrLexicon.CHILD_NODE_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) { - childNodes.add(this.childNodeDefinitionFrom(nodeTypeGraph, childLocation)); - } else { - throw new IllegalStateException("Unexpected child of node type at: " + childLocation); + if (childDefns != null) { + for (NodeDefinition childNodeDefn : childDefns) { + childNodes.add(childNodeDefinitionFrom(childNodeDefn)); } } - Map nodeProperties = nodeTypeNode.getPropertiesByName(); - - ValueFactories valueFactories = context.getValueFactories(); - NameFactory nameFactory = valueFactories.getNameFactory(); - ValueFactory booleanFactory = valueFactories.getBooleanFactory(); - - Name name = nameFactory.create(getFirstPropertyValue(nodeProperties.get(JcrLexicon.NODE_TYPE_NAME))); - Name primaryItemName = nameFactory.create(getFirstPropertyValue(nodeProperties.get(JcrLexicon.PRIMARY_ITEM_NAME))); - boolean mixin = booleanFactory.create(getFirstPropertyValue(nodeProperties.get(JcrLexicon.IS_MIXIN))); - boolean isAbstract = booleanFactory.create(getFirstPropertyValue(nodeProperties.get(JcrLexicon.IS_ABSTRACT))); - boolean queryable = booleanFactory.create(getFirstPropertyValue(nodeProperties.get(JcrLexicon.IS_QUERYABLE))); - boolean orderableChildNodes = booleanFactory.create(getFirstPropertyValue(nodeProperties.get(JcrLexicon.HAS_ORDERABLE_CHILD_NODES))); + Name name = nameFactory.create(nodeType.getName()); + Name primaryItemName = nameFactory.create(nodeType.getPrimaryItemName()); + boolean mixin = nodeType.isMixin(); + boolean isAbstract = nodeType.isAbstract(); + boolean queryable = nodeType.isQueryable(); + boolean orderableChildNodes = nodeType.hasOrderableChildNodes(); return new JcrNodeType(this.context, this, name, supertypes, primaryItemName, childNodes, properties, mixin, isAbstract, queryable, orderableChildNodes); } - private JcrPropertyDefinition propertyDefinitionFrom( Subgraph nodeTypeGraph, - Location propertyLocation ) { - Node propertyDefinitionNode = nodeTypeGraph.getNode(propertyLocation); - Map properties = propertyDefinitionNode.getPropertiesByName(); - - ValueFactories valueFactories = context.getValueFactories(); - NameFactory nameFactory = valueFactories.getNameFactory(); - ValueFactory booleanFactory = valueFactories.getBooleanFactory(); - - Name propertyName = nameFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.NAME))); - int onParentVersionBehavior = OnParentVersionAction.valueFromName((String)getFirstPropertyValue(properties.get(JcrLexicon.ON_PARENT_VERSION))); - int requiredType = PROPERTY_TYPE_VALUES_FROM_NAME.get(getFirstPropertyValue(properties.get(JcrLexicon.REQUIRED_TYPE))); - - boolean mandatory = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.MANDATORY))); - boolean multiple = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.MULTIPLE))); - boolean autoCreated = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.AUTO_CREATED))); - boolean isProtected = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.PROTECTED))); - Boolean ftsObj = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.IS_FULL_TEXT_SEARCHABLE))); - boolean fullTextSearchable = ftsObj != null ? ftsObj.booleanValue() : false; - Boolean qoObj = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.IS_QUERY_ORDERABLE))); - boolean queryOrderable = qoObj != null ? qoObj.booleanValue() : false; - - Value[] defaultValues; - Property defaultValuesProperty = properties.get(JcrLexicon.DEFAULT_VALUES); - if (defaultValuesProperty != null) { - List values = new ArrayList(); - - for (Object value : defaultValuesProperty) { - values.add(new JcrValue(this.context.getValueFactories(), (SessionCache)null, requiredType, value)); + private JcrPropertyDefinition propertyDefinitionFrom( PropertyDefinition propDefn ) throws RepositoryException { + Name propertyName = nameFactory.create(propDefn.getName()); + int onParentVersionBehavior = propDefn.getOnParentVersion(); + int requiredType = propDefn.getRequiredType(); + boolean mandatory = propDefn.isMandatory(); + boolean multiple = propDefn.isMultiple(); + boolean autoCreated = propDefn.isAutoCreated(); + boolean isProtected = propDefn.isProtected(); + boolean fullTextSearchable = propDefn.isFullTextSearchable(); + boolean queryOrderable = propDefn.isQueryOrderable(); + + Value[] defaultValues = propDefn.getDefaultValues(); + if (defaultValues != null) { + for (int i = 0; i != defaultValues.length; ++i) { + Value value = defaultValues[i]; + defaultValues[i] = new JcrValue(this.context.getValueFactories(), null, value); } - defaultValues = values.toArray(new Value[values.size()]); } else { defaultValues = new Value[0]; } - String[] valueConstraints; - Property constraintsProperty = properties.get(JcrLexicon.VALUE_CONSTRAINTS); - if (constraintsProperty != null) { - List constraints = new ArrayList(); - - for (Object value : constraintsProperty) { - constraints.add((String)value); - } - valueConstraints = constraints.toArray(new String[constraints.size()]); - } else { - valueConstraints = new String[0]; - } - - String[] queryOperators; - Property operatorsProperty = properties.get(JcrLexicon.QUERY_OPERATORS); - if (operatorsProperty != null) { - List operators = new ArrayList(); - - for (Object value : operatorsProperty) { - operators.add((String)value); - } - queryOperators = operators.toArray(new String[operators.size()]); - } else { - queryOperators = new String[0]; - } + String[] valueConstraints = propDefn.getValueConstraints(); + String[] queryOperators = propDefn.getAvailableQueryOperators(); + if (valueConstraints == null) valueConstraints = new String[0]; + if (queryOperators == null) queryOperators = new String[0]; return new JcrPropertyDefinition(this.context, null, propertyName, onParentVersionBehavior, autoCreated, mandatory, isProtected, defaultValues, requiredType, valueConstraints, multiple, fullTextSearchable, queryOrderable, queryOperators); } - private JcrNodeDefinition childNodeDefinitionFrom( Subgraph nodeTypeGraph, - Location childNodeLocation ) { - Node childNodeDefinitionNode = nodeTypeGraph.getNode(childNodeLocation); - Map properties = childNodeDefinitionNode.getPropertiesByName(); + private JcrNodeDefinition childNodeDefinitionFrom( NodeDefinition childNodeDefn ) { + Name childNodeName = nameFactory.create(childNodeDefn.getName()); + Name defaultPrimaryTypeName = nameFactory.create(childNodeDefn.getDefaultPrimaryTypeName()); + int onParentVersion = childNodeDefn.getOnParentVersion(); - ValueFactories valueFactories = context.getValueFactories(); - NameFactory nameFactory = valueFactories.getNameFactory(); - ValueFactory booleanFactory = valueFactories.getBooleanFactory(); - - Name childNodeName = nameFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.NAME))); - Name defaultPrimaryTypeName = nameFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.DEFAULT_PRIMARY_TYPE))); - int onParentVersion = OnParentVersionAction.valueFromName((String)getFirstPropertyValue(properties.get(JcrLexicon.ON_PARENT_VERSION))); - - boolean mandatory = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.MANDATORY))); - boolean allowsSns = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.SAME_NAME_SIBLINGS))); - boolean autoCreated = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.AUTO_CREATED))); - boolean isProtected = booleanFactory.create(getFirstPropertyValue(properties.get(JcrLexicon.PROTECTED))); + boolean mandatory = childNodeDefn.isMandatory(); + boolean allowsSns = childNodeDefn.allowsSameNameSiblings(); + boolean autoCreated = childNodeDefn.isAutoCreated(); + boolean isProtected = childNodeDefn.isProtected(); Name[] requiredTypes; - Property requiredTypeNamesProperty = properties.get(JcrLexicon.REQUIRED_PRIMARY_TYPES); - if (requiredTypeNamesProperty != null) { - List names = new ArrayList(requiredTypeNamesProperty.size()); - for (Object value : requiredTypeNamesProperty) { - names.add(nameFactory.create(value)); + String[] requiredTypeNames = childNodeDefn.getRequiredPrimaryTypeNames(); + if (requiredTypeNames != null) { + List names = new ArrayList(requiredTypeNames.length); + for (String typeName : requiredTypeNames) { + names.add(nameFactory.create(typeName)); } - requiredTypes = names.toArray(new Name[names.size()]); } else { requiredTypes = new Name[0]; @@ -1910,10 +1738,6 @@ class RepositoryNodeTypeManager { allowsSns, defaultPrimaryTypeName, requiredTypes); } - private Object getFirstPropertyValue( Property property ) { - return property != null ? property.getFirstValue() : null; - } - /** * Finds the named type in the given list of types pending registration if it exists, else returns the type definition from * the repository @@ -1945,48 +1769,35 @@ class RepositoryNodeTypeManager { * @throws RepositoryException if any of the names in the array of supertype names does not correspond to an * already-registered node type or a node type that is pending registration */ - private List supertypesFor( Node nodeType, + private List supertypesFor( NodeTypeDefinition nodeType, List pendingTypes ) throws RepositoryException { assert nodeType != null; - Property supertypesProperty = nodeType.getProperty(JcrLexicon.SUPERTYPES); - Object[] supertypesArray; - - // If no supertypes are provided, assume nt:base as a supertype - if (supertypesProperty == null || supertypesProperty.size() == 0) { - supertypesArray = new Object[0]; - } else { - supertypesArray = supertypesProperty.getValuesAsArray(); - } List supertypes = new LinkedList(); - Property isMixinProperty = nodeType.getProperty(JcrLexicon.IS_MIXIN); - boolean isMixin = isMixinProperty != null && Boolean.valueOf(isMixinProperty.getFirstValue().toString()); + boolean isMixin = nodeType.isMixin(); boolean needsPrimaryAncestor = !isMixin; + String nodeTypeName = nodeType.getName(); - for (int i = 0; i < supertypesArray.length; i++) { - JcrNodeType supertype = findTypeInMapOrList((Name)supertypesArray[i], pendingTypes); + for (String supertypeNameStr : nodeType.getDeclaredSupertypeNames()) { + Name supertypeName = nameFactory.create(supertypeNameStr); + JcrNodeType supertype = findTypeInMapOrList(supertypeName, pendingTypes); if (supertype == null) { - Name nodeTypeName = nodeType.getLocation().getPath().getLastSegment().getName(); - throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidSupertypeName.text(supertypesArray[i], nodeTypeName)); + throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidSupertypeName.text(supertypeNameStr, nodeTypeName)); } - needsPrimaryAncestor &= supertype.isMixin(); supertypes.add(supertype); } // primary types (other than nt:base) always have at least one ancestor that's a primary type - nt:base if (needsPrimaryAncestor) { - Property nameProperty = nodeType.getProperty(JcrLexicon.NODE_TYPE_NAME); - Name nodeName = context.getValueFactories().getNameFactory().create(nameProperty.getFirstValue()); - + Name nodeName = nameFactory.create(nodeTypeName); if (!JcrNtLexicon.BASE.equals(nodeName)) { JcrNodeType ntBase = findTypeInMapOrList(JcrNtLexicon.BASE, pendingTypes); assert ntBase != null; supertypes.add(0, ntBase); } } - return supertypes; } @@ -2112,8 +1923,7 @@ class RepositoryNodeTypeManager { /** * Validates that the given node type definition is valid under the ModeShape and JCR type rules within the given context. *

    - * See {@link #registerNodeTypes(JcrNodeTypeSource)} for the list of criteria that determine whether a node type definition is - * valid. + * See {@link #registerNodeTypes(Iterable)} for the list of criteria that determine whether a node type definition is valid. *

    * * @param nodeType the node type to attempt to validate @@ -2128,8 +1938,9 @@ class RepositoryNodeTypeManager { validate(supertypes, nodeTypeName.getString(this.context.getNamespaceRegistry())); List supertypeNames = new ArrayList(supertypes.size()); - for (JcrNodeType supertype : supertypes) + for (JcrNodeType supertype : supertypes) { supertypeNames.add(supertype.getInternalName()); + } boolean foundExact = false; boolean foundResidual = false; Index: modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties =================================================================== --- modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (revision 2037) +++ modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (working copy) @@ -114,8 +114,11 @@ errorObtainingWorkspaceNames = Error while obtaining the workspace names for the errorObtainingDefaultWorkspaceName = Error while obtaining the default workspace names for the "{0}" repository: {1} workspaceNameIsInvalid = "{1}" is not a valid workspace name for the "{0}" repository errorVerifyingWorkspaceName =Error validating the workspace name "{1}" for the "{0}" repository\: {2} + typeNotFound=No type exists with name "{0}" supertypeNotFound=Could not find type "{0}" which is a required supertype of type "{1}" +errorImportingNodeTypeContent = Error importing node types from "{0}": {1} +nodeTypesNotFoundInXml = No valid node types elements found in the XML in "{0}" systemSourceNameOptionValueDoesNotReferenceExistingSource = The JCR Repository 'SYSTEM_SOURCE_NAME' option value "{0}" references an invalid or non-existant source "{1}" systemSourceNameOptionValueDoesNotReferenceValidWorkspace = The JCR Repository 'SYSTEM_SOURCE_NAME' option value "{0}" references an invalid or non-existant workspace in the "{1}" source Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java (working copy) @@ -85,9 +85,10 @@ public abstract class AbstractJcrTest { rntm = new RepositoryNodeTypeManager(repository, true); try { - rntm.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/modeshape/jcr/jsr_283_builtins.cnd", - "/org/modeshape/jcr/modeshape_builtins.cnd"})); - rntm.registerNodeTypes(new NodeTemplateNodeTypeSource(Vehicles.getNodeTypes(context))); + CndNodeTypeReader cndReader = new CndNodeTypeReader(context); + cndReader.readBuiltInTypes(); + rntm.registerNodeTypes(cndReader); + rntm.registerNodeTypes(Vehicles.getNodeTypes(context)); } catch (RepositoryException re) { re.printStackTrace(); throw new IllegalStateException("Could not load node type definition files", re); Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java (working copy) @@ -36,7 +36,7 @@ import java.util.List; import java.util.Map; import javax.jcr.RepositoryException; import javax.jcr.nodetype.ConstraintViolationException; -import javax.jcr.nodetype.NodeTypeTemplate; +import javax.jcr.nodetype.NodeTypeDefinition; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @@ -149,9 +149,10 @@ public abstract class AbstractSessionTest { when(repository.getRepositoryTypeManager()).thenReturn(repoTypeManager); try { - this.repoTypeManager.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/modeshape/jcr/jsr_283_builtins.cnd", - "/org/modeshape/jcr/modeshape_builtins.cnd"})); - this.repoTypeManager.registerNodeTypes(new NodeTemplateNodeTypeSource(getTestTypes())); + CndNodeTypeReader cndReader = new CndNodeTypeReader(context); + cndReader.readBuiltInTypes(); + repoTypeManager.registerNodeTypes(cndReader); + repoTypeManager.registerNodeTypes(getTestTypes()); } catch (RepositoryException re) { re.printStackTrace(); @@ -194,7 +195,7 @@ public abstract class AbstractSessionTest { } @SuppressWarnings( "unused" ) - protected List getTestTypes() throws ConstraintViolationException { + protected List getTestTypes() throws ConstraintViolationException { return Collections.emptyList(); } Index: modeshape-jcr/src/test/java/org/modeshape/jcr/CndNodeTypeRegistrationTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/CndNodeTypeRegistrationTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/CndNodeTypeRegistrationTest.java (working copy) @@ -51,7 +51,6 @@ public class CndNodeTypeRegistrationTest { private ExecutionContext context; private RepositoryNodeTypeManager repoTypeManager; - private JcrNodeTypeSource nodeTypes; @Mock protected JcrRepository repository; @@ -65,8 +64,9 @@ public class CndNodeTypeRegistrationTest { repoTypeManager = new RepositoryNodeTypeManager(repository, true); try { - this.repoTypeManager.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/modeshape/jcr/jsr_283_builtins.cnd", - "/org/modeshape/jcr/modeshape_builtins.cnd"})); + CndNodeTypeReader cndReader = new CndNodeTypeReader(context); + cndReader.readBuiltInTypes(); + repoTypeManager.registerNodeTypes(cndReader); } catch (RepositoryException re) { re.printStackTrace(); throw new IllegalStateException("Could not load node type definition files", re); @@ -80,24 +80,25 @@ public class CndNodeTypeRegistrationTest { @Ignore @Test( expected = RepositoryException.class ) public void shouldNotAllowRedefinitionOfExistingType() throws Exception { - nodeTypes = new CndNodeTypeSource(CND_LOCATION + "existingType.cnd"); - - repoTypeManager.registerNodeTypes(nodeTypes); + CndNodeTypeReader cndFactory = new CndNodeTypeReader(context); + cndFactory.read(CND_LOCATION + "existingType.cnd"); + repoTypeManager.registerNodeTypes(cndFactory); } @Test public void shouldLoadMagnoliaTypes() throws Exception { - nodeTypes = new CndNodeTypeSource("/magnolia.cnd"); - - repoTypeManager.registerNodeTypes(nodeTypes); + CndNodeTypeReader cndFactory = new CndNodeTypeReader(context); + cndFactory.read("/magnolia.cnd"); + repoTypeManager.registerNodeTypes(cndFactory); } @Ignore @Test public void shouldRegisterValidTypes() throws Exception { - nodeTypes = new CndNodeTypeSource(CND_LOCATION + "validType.cnd"); + CndNodeTypeReader cndFactory = new CndNodeTypeReader(context); + cndFactory.read(CND_LOCATION + "validType.cnd"); + repoTypeManager.registerNodeTypes(cndFactory); - repoTypeManager.registerNodeTypes(nodeTypes); Name testNodeName = context.getValueFactories().getNameFactory().create(TestLexicon.Namespace.URI, "testType"); NodeType nodeType = repoTypeManager.getNodeType(testNodeName); Index: modeshape-jcr/src/test/java/org/modeshape/jcr/ItemDefinitionTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/ItemDefinitionTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/ItemDefinitionTest.java (working copy) @@ -34,6 +34,7 @@ import java.util.List; import javax.jcr.PropertyType; import javax.jcr.Value; import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.nodetype.NodeTypeTemplate; import org.junit.After; import org.junit.Before; @@ -194,7 +195,7 @@ public class ItemDefinitionTest extends AbstractSessionTest { @SuppressWarnings( "unchecked" ) @Override - protected List getTestTypes() throws ConstraintViolationException { + protected List getTestTypes() throws ConstraintViolationException { NodeTypeTemplate nodeA = new JcrNodeTypeTemplate(context); nodeA.setName("modetest:nodeA"); @@ -235,6 +236,6 @@ public class ItemDefinitionTest extends AbstractSessionTest { nodeCSingleProp2Long.setRequiredType(PropertyType.LONG); nodeC.getPropertyDefinitionTemplates().add(nodeCSingleProp2Long); - return Arrays.asList(new NodeTypeTemplate[] {nodeA, nodeB, nodeC}); + return Arrays.asList(new NodeTypeDefinition[] {nodeA, nodeB, nodeC}); } } Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JackrabbitXmlNodeTypeRegistrationTest.java new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JackrabbitXmlNodeTypeRegistrationTest.java (working copy) @@ -0,0 +1,487 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.version.OnParentVersionAction; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.modeshape.common.collection.Problem; +import org.modeshape.graph.ExecutionContext; +import org.modeshape.graph.property.Name; + +/** + * Test of reading node type definitions from Jackrabbit XML files. These test cases focus on ensuring that an import of a type + * from a Jackrabbit XML file registers the expected type rather than attempting to validate all of the type registration + * functionality already tested in {@link TypeRegistrationTest}. + */ +public class JackrabbitXmlNodeTypeRegistrationTest { + + /** Location of XML files for this test */ + private static final String XML_LOCATION = "/xmlNodeTypeRegistration/"; + + private ExecutionContext context; + private RepositoryNodeTypeManager repoTypeManager; + private JackrabbitXmlNodeTypeReader factory; + @Mock + protected JcrRepository repository; + + @Before + public void beforeEach() throws Exception { + MockitoAnnotations.initMocks(this); + context = new ExecutionContext(); + context.getNamespaceRegistry().register(TestLexicon.Namespace.PREFIX, TestLexicon.Namespace.URI); + + when(repository.getExecutionContext()).thenReturn(context); + + repoTypeManager = new RepositoryNodeTypeManager(repository, true); + try { + CndNodeTypeReader cndFactory = new CndNodeTypeReader(context); + cndFactory.readBuiltInTypes(); + repoTypeManager.registerNodeTypes(cndFactory); + } catch (RepositoryException re) { + re.printStackTrace(); + throw new IllegalStateException("Could not load node type definition files", re); + } catch (IOException ioe) { + ioe.printStackTrace(); + throw new IllegalStateException("Could not access node type definition files", ioe); + } + factory = new JackrabbitXmlNodeTypeReader(context); + } + + @Test + public void shouldLoadCustomNodeTypes() throws Exception { + register(XML_LOCATION + "custom_nodetypes.xml"); + + NodeType nodeType = repoTypeManager.getNodeType(name("mgnl:metaData")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(2)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mix:referenceable")); + assertThat(nodeType.getDeclaredSupertypes()[1].getName(), is("nt:hierarchyNode")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(0)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(1)); + + JcrPropertyDefinition property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + // mgnl:content + nodeType = repoTypeManager.getNodeType(name("mgnl:content")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(2)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mix:referenceable")); + assertThat(nodeType.getDeclaredSupertypes()[1].getName(), is("nt:hierarchyNode")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(2)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(2)); + + JcrNodeDefinition childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[0]; + assertThat(childNode.getName(), is("*")); + assertThat(childNode.getDefaultPrimaryType(), is(nullValue())); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("nt:base")); + assertThat(childNode.allowsSameNameSiblings(), is(true)); + assertThat(childNode.isAutoCreated(), is(false)); + assertThat(childNode.isMandatory(), is(false)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[1]; + assertThat(childNode.getName(), is("MetaData")); + assertThat(childNode.getDefaultPrimaryType().getName(), is("mgnl:metaData")); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("mgnl:metaData")); + assertThat(childNode.allowsSameNameSiblings(), is(false)); + assertThat(childNode.isAutoCreated(), is(true)); + assertThat(childNode.isMandatory(), is(true)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(true)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[1]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + // mgnl:group + nodeType = repoTypeManager.getNodeType(name("mgnl:group")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mgnl:content")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(0)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(0)); + + // mgnl:folder + nodeType = repoTypeManager.getNodeType(name("mgnl:folder")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(2)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mix:referenceable")); + assertThat(nodeType.getDeclaredSupertypes()[1].getName(), is("nt:folder")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(2)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(2)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[0]; + assertThat(childNode.getName(), is("*")); + assertThat(childNode.getDefaultPrimaryType(), is(nullValue())); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("nt:base")); + assertThat(childNode.allowsSameNameSiblings(), is(true)); + assertThat(childNode.isAutoCreated(), is(false)); + assertThat(childNode.isMandatory(), is(false)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[1]; + assertThat(childNode.getName(), is("MetaData")); + assertThat(childNode.getDefaultPrimaryType().getName(), is("mgnl:metaData")); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("mgnl:metaData")); + assertThat(childNode.allowsSameNameSiblings(), is(false)); + assertThat(childNode.isAutoCreated(), is(true)); + assertThat(childNode.isMandatory(), is(true)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(true)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[1]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + // mgnl:user + nodeType = repoTypeManager.getNodeType(name("mgnl:user")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mgnl:content")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(0)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(0)); + + // mgnl:user + nodeType = repoTypeManager.getNodeType(name("mgnl:resource")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(false)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("nt:resource")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(0)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(1)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + // mgnl:contentNode + nodeType = repoTypeManager.getNodeType(name("mgnl:contentNode")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(2)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mix:referenceable")); + assertThat(nodeType.getDeclaredSupertypes()[1].getName(), is("nt:hierarchyNode")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(2)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(2)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[0]; + assertThat(childNode.getName(), is("*")); + assertThat(childNode.getDefaultPrimaryType(), is(nullValue())); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("nt:base")); + assertThat(childNode.allowsSameNameSiblings(), is(true)); + assertThat(childNode.isAutoCreated(), is(false)); + assertThat(childNode.isMandatory(), is(false)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[1]; + assertThat(childNode.getName(), is("MetaData")); + assertThat(childNode.getDefaultPrimaryType().getName(), is("mgnl:metaData")); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("mgnl:metaData")); + assertThat(childNode.allowsSameNameSiblings(), is(false)); + assertThat(childNode.isAutoCreated(), is(true)); + assertThat(childNode.isMandatory(), is(true)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(true)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[1]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + // mgnl:role + nodeType = repoTypeManager.getNodeType(name("mgnl:role")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("mgnl:content")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(0)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(0)); + + // mgnl:reserve + nodeType = repoTypeManager.getNodeType(name("mgnl:reserve")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("nt:hierarchyNode")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(1)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(1)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[0]; + assertThat(childNode.getName(), is("*")); + assertThat(childNode.getDefaultPrimaryType(), is(nullValue())); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("nt:base")); + assertThat(childNode.allowsSameNameSiblings(), is(true)); + assertThat(childNode.isAutoCreated(), is(false)); + assertThat(childNode.isMandatory(), is(false)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + } + + @Test + public void shouldLoadMagnoliaForumTypes() throws Exception { + register(XML_LOCATION + "magnolia_forum_nodetypes.xml"); + } + + @Test + public void shouldLoadOwfeNodeTypes() throws Exception { + register(XML_LOCATION + "owfe_nodetypes.xml"); + + NodeType nodeType = repoTypeManager.getNodeType(name("workItem")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("nt:hierarchyNode")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(1)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(1)); + + JcrNodeDefinition childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[0]; + assertThat(childNode.getName(), is("*")); + assertThat(childNode.getDefaultPrimaryType(), is(nullValue())); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("nt:hierarchyNode")); + assertThat(childNode.allowsSameNameSiblings(), is(true)); + assertThat(childNode.isAutoCreated(), is(false)); + assertThat(childNode.isMandatory(), is(false)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.VERSION)); + + JcrPropertyDefinition property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + + nodeType = repoTypeManager.getNodeType(name("expression")); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(false)); + assertThat(nodeType.isMixin(), is(false)); + assertThat(nodeType.isQueryable(), is(true)); + assertThat(nodeType.hasOrderableChildNodes(), is(true)); + assertThat(nodeType.getPrimaryItemName(), is(nullValue())); + assertThat(nodeType.getDeclaredSupertypes().length, is(1)); + assertThat(nodeType.getDeclaredSupertypes()[0].getName(), is("nt:hierarchyNode")); + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(1)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(1)); + + childNode = (JcrNodeDefinition)nodeType.getDeclaredChildNodeDefinitions()[0]; + assertThat(childNode.getName(), is("*")); + assertThat(childNode.getDefaultPrimaryType(), is(nullValue())); + assertThat(childNode.getRequiredPrimaryTypes().length, is(1)); + assertThat(childNode.getRequiredPrimaryTypes()[0].getName(), is("nt:hierarchyNode")); + assertThat(childNode.allowsSameNameSiblings(), is(true)); + assertThat(childNode.isAutoCreated(), is(false)); + assertThat(childNode.isMandatory(), is(false)); + assertThat(childNode.isProtected(), is(false)); + assertThat(childNode.getOnParentVersion(), is(OnParentVersionAction.VERSION)); + + property = (JcrPropertyDefinition)nodeType.getDeclaredPropertyDefinitions()[0]; + assertThat(property.getName(), is("*")); + assertThat(property.getRequiredType(), is(PropertyType.UNDEFINED)); + assertThat(property.getValueConstraints().length, is(0)); + assertThat(property.getDefaultValues().length, is(0)); + assertThat(property.isAutoCreated(), is(false)); + assertThat(property.isMandatory(), is(false)); + assertThat(property.isMultiple(), is(false)); + assertThat(property.isProtected(), is(false)); + assertThat(property.getOnParentVersion(), is(OnParentVersionAction.COPY)); + } + + @Test + public void shouldLoadAllMagnoliaTypes() throws Exception { + register(XML_LOCATION + "magnolia_forum_nodetypes.xml", XML_LOCATION + "custom_nodetypes.xml", XML_LOCATION + + "owfe_nodetypes.xml"); + } + + protected List register( String... resourceNames ) throws Exception { + for (String resourceName : resourceNames) { + factory.read(resourceName); + } + if (factory.getProblems().hasProblems()) { + System.out.println("Problems reading node types:" + factory); + for (Problem problem : factory.getProblems()) { + System.out.println(" " + problem); + } + } + assertThat(factory.getProblems().hasProblems(), is(false)); + return repoTypeManager.registerNodeTypes(Arrays.asList(factory.getNodeTypeDefinitions())); + } + + protected Name name( String name ) { + return context.getValueFactories().getNameFactory().create(name); + } +} Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrEngineTest.java new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrEngineTest.java (working copy) @@ -0,0 +1,157 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.Assert.assertThat; +import java.net.URL; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; +import org.junit.After; +import org.junit.Test; +import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; +import org.modeshape.jcr.JcrRepository.Option; + +/** + * + */ +public class JcrEngineTest { + + protected static URL resourceUrl( String name ) { + return JcrQueryManagerTest.class.getClassLoader().getResource(name); + } + + private JcrConfiguration configuration; + private JcrEngine engine; + private JcrRepository repository; + private Session session; + + @After + public void afterEach() { + configuration = null; + + try { + if (session != null) { + session.logout(); + } + } finally { + session = null; + try { + if (engine != null) { + engine.shutdown(); + } + } finally { + engine = null; + } + } + } + + @Test + public void shouldCreateRepositoryConfiguredWithOneCompactNodeTypeDefinitionFile() throws Exception { + configuration = new JcrConfiguration(); + configuration.repositorySource("car-source") + .usingClass(InMemoryRepositorySource.class) + .setDescription("The automobile content"); + configuration.repository("cars") + .setSource("car-source") + .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0") + .addNodeTypes(resourceUrl("cars.cnd")) + .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN); + engine = configuration.build(); + engine.start(); + repository = engine.getRepository("cars"); + session = repository.login(); + + assertNodeType("car:Car", false, false, true, false, null, 0, 11, "nt:unstructured", "mix:created"); + } + +// @Test +// public void shouldCreateRepositoryConfiguredWithOneXmlNodeTypeDefinitionFiles() throws Exception { +// configuration = new JcrConfiguration(); +// configuration.repositorySource("car-source") +// .usingClass(InMemoryRepositorySource.class) +// .setDescription("The automobile content"); +// configuration.repository("cars") +// .setSource("car-source") +// .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0") +// .addNodeTypes(resourceUrl("xmlNodeTypeRegistration/owfe_nodetypes.xml")) +// .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN); +// engine = configuration.build(); +// engine.start(); +// +// repository = engine.getRepository("cars"); +// session = repository.login(); +// +// assertNodeType("mgnl:workItem", false, false, true, true, null, 1, 1, "nt:hierarchyNode"); +// } + +// @Test +// public void shouldCreateRepositoryConfiguredWithMultipleNodeTypeDefinitionFiles() throws Exception { +// configuration = new JcrConfiguration(); +// configuration.repositorySource("car-source") +// .usingClass(InMemoryRepositorySource.class) +// .setDescription("The automobile content"); +// configuration.repository("cars") +// .setSource("car-source") +// .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0") +// .addNodeTypes(resourceUrl("cars.cnd")) +// .addNodeTypes(resourceUrl("xmlNodeTypeRegistration/owfe_nodetypes.xml")) +// .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN); +// engine = configuration.build(); +// engine.start(); +// +// repository = engine.getRepository("cars"); +// session = repository.login(); +// +// assertNodeType("car:Car", false, false, true, false, null, 0, 11, "nt:unstructured", "mix:created"); +// assertNodeType("mgnl:workItem", false, false, true, true, null, 1, 1, "nt:hierarchyNode"); +// } + + protected void assertNodeType( String name, + boolean isAbstract, + boolean isMixin, + boolean isQueryable, + boolean hasOrderableChildNodes, + String primaryItemName, + int numberOfDeclaredChildNodeDefinitions, + int numberOfDeclaredPropertyDefinitions, + String... supertypes ) throws Exception { + NodeType nodeType = session.getWorkspace().getNodeTypeManager().getNodeType(name); + assertThat(nodeType, is(notNullValue())); + assertThat(nodeType.isAbstract(), is(isAbstract)); + assertThat(nodeType.isMixin(), is(isMixin)); + assertThat(nodeType.isQueryable(), is(isQueryable)); + assertThat(nodeType.hasOrderableChildNodes(), is(hasOrderableChildNodes)); + assertThat(nodeType.getPrimaryItemName(), is(primaryItemName)); + assertThat(nodeType.getDeclaredSupertypes().length, is(supertypes.length)); + for (int i = 0; i != supertypes.length; ++i) { + assertThat(nodeType.getDeclaredSupertypes()[i].getName(), is(supertypes[i])); + } + assertThat(nodeType.getDeclaredChildNodeDefinitions().length, is(numberOfDeclaredChildNodeDefinitions)); + assertThat(nodeType.getDeclaredPropertyDefinitions().length, is(numberOfDeclaredPropertyDefinitions)); + + } + +} Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrMultiValuePropertyTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrMultiValuePropertyTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrMultiValuePropertyTest.java (working copy) @@ -26,15 +26,12 @@ package org.modeshape.jcr; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.junit.Assert.assertThat; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.Value; import javax.jcr.ValueFormatException; -import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.nodetype.PropertyDefinition; import org.junit.Before; import org.junit.BeforeClass; @@ -138,9 +135,7 @@ public class JcrMultiValuePropertyTest extends AbstractJcrTest { propDefns.add(undefinedDefn); // Add the node type ... - Collection defns = new ArrayList(); - defns.add(nodeType); - rntm.registerNodeTypes(defns, false); + rntm.registerNodeType(nodeType); } @Override Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTypeManagerTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTypeManagerTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTypeManagerTest.java (working copy) @@ -125,8 +125,10 @@ public final class JcrNodeTypeManagerTest extends TestSuite { final String SOURCE = "store"; JcrConfiguration config = new JcrConfiguration(); - config.repositorySource("store").usingClass(InMemoryRepositorySource.class).setRetryLimit(100).setProperty("defaultWorkspaceName", - WORKSPACE); + config.repositorySource("store") + .usingClass(InMemoryRepositorySource.class) + .setRetryLimit(100) + .setProperty("defaultWorkspaceName", WORKSPACE); config.repository(REPOSITORY).setSource(SOURCE).setOption(Option.JAAS_LOGIN_CONFIG_NAME, "modeshape-jcr"); config.save(); @@ -186,7 +188,9 @@ public final class JcrNodeTypeManagerTest extends TestSuite { @Test public void shouldAllowDisjunctiveResidualChildNodeDefinitions() throws Exception { // This is an extended test of the MODE-698 fix - nodeTypeMgr.registerNodeTypes(new CndNodeTypeSource("/magnolia.cnd")); + CndNodeTypeReader factory = new CndNodeTypeReader(engine.getExecutionContext()); + factory.read("/magnolia.cnd"); + nodeTypeMgr.registerNodeTypes(factory.getNodeTypeDefinitions(), false); session.getWorkspace().getNamespaceRegistry().registerNamespace("mgnl", "http://www.magnolia.info/jcr/mgnl"); assertThat(nodeTypeMgr.getNodeType("mgnl:content"), is(notNullValue())); Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrPropertyDefinitionTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrPropertyDefinitionTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrPropertyDefinitionTest.java (working copy) @@ -33,6 +33,7 @@ import javax.jcr.PropertyType; import javax.jcr.Value; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.nodetype.NodeTypeTemplate; import javax.jcr.nodetype.PropertyDefinition; @@ -571,7 +572,7 @@ public class JcrPropertyDefinitionTest extends AbstractSessionTest { @SuppressWarnings( "unchecked" ) @Override - protected List getTestTypes() throws ConstraintViolationException { + protected List getTestTypes() throws ConstraintViolationException { NodeTypeTemplate constrainedType = new JcrNodeTypeTemplate(this.context); constrainedType.setName("modetest:constrainedType"); @@ -623,7 +624,7 @@ public class JcrPropertyDefinitionTest extends AbstractSessionTest { propString.setValueConstraints(EXPECTED_STRING_CONSTRAINTS); constrainedType.getPropertyDefinitionTemplates().add(propString); - return Collections.singletonList(constrainedType); + return Collections.singletonList((NodeTypeDefinition)constrainedType); } } Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrSingleValuePropertyTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrSingleValuePropertyTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrSingleValuePropertyTest.java (working copy) @@ -29,8 +29,6 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import javax.jcr.Binary; import javax.jcr.Node; @@ -38,7 +36,6 @@ import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.Value; import javax.jcr.ValueFormatException; -import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.nodetype.PropertyDefinition; import org.junit.Before; import org.junit.BeforeClass; @@ -129,9 +126,7 @@ public class JcrSingleValuePropertyTest extends AbstractJcrTest { propDefns.add(undefinedDefn); // Add the node type ... - Collection defns = new ArrayList(); - defns.add(nodeType); - rntm.registerNodeTypes(defns, false); + rntm.registerNodeType(nodeType); } @Override Index: modeshape-jcr/src/test/java/org/modeshape/jcr/MixinTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/MixinTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/MixinTest.java (working copy) @@ -33,6 +33,7 @@ import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.version.OnParentVersionAction; import org.junit.After; import org.junit.Before; @@ -383,7 +384,7 @@ public class MixinTest extends AbstractSessionTest { @SuppressWarnings( {"unchecked", "deprecation"} ) @Override - protected List getTestTypes() throws ConstraintViolationException { + protected List getTestTypes() throws ConstraintViolationException { NodeTypeTemplate mixinTypeA = new JcrNodeTypeTemplate(this.context); mixinTypeA.setName("mixinTypeA"); mixinTypeA.setMixin(true); @@ -470,8 +471,8 @@ public class MixinTest extends AbstractSessionTest { propertyA.setRequiredType(PropertyType.STRING); primaryTypeA.getPropertyDefinitionTemplates().add(propertyA); - return Arrays.asList(new javax.jcr.nodetype.NodeTypeTemplate[] {mixinTypeA, mixinTypeB, mixinTypeC, - mixinTypeWithAutoChild, mixinTypeWithAutoProperty, primaryTypeA,}); + return Arrays.asList(new NodeTypeDefinition[] {mixinTypeA, mixinTypeB, mixinTypeC, mixinTypeWithAutoChild, + mixinTypeWithAutoProperty, primaryTypeA,}); } } Index: modeshape-jcr/src/test/java/org/modeshape/jcr/TypeRegistrationTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/TypeRegistrationTest.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/TypeRegistrationTest.java (working copy) @@ -120,7 +120,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.setName(TEST_TYPE_NAME); ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base"}); - JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate, false); + JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate); assertThat(testNodeType.getName(), is(TEST_TYPE_NAME)); JcrNodeType nodeTypeFromRepo = repoTypeManager.getNodeType(testTypeName); @@ -131,7 +131,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { @Test( expected = NodeTypeExistsException.class ) public void shouldNotAllowModificationIfAllowUpdatesIsFalse() throws Exception { ntTemplate.setName("nt:base"); - repoTypeManager.registerNodeType(ntTemplate, false); + repoTypeManager.registerNodeType(ntTemplate); } @Test( expected = NodeTypeExistsException.class ) @@ -140,14 +140,14 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.setName(TEST_TYPE_NAME); ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base"}); - JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate, false); + JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate); assertThat(testNodeType.getName(), is(TEST_TYPE_NAME)); JcrNodeType nodeTypeFromRepo = repoTypeManager.getNodeType(testTypeName); assertThat(nodeTypeFromRepo, is(notNullValue())); assertThat(nodeTypeFromRepo.getName(), is(TEST_TYPE_NAME)); - testNodeType = repoTypeManager.registerNodeType(ntTemplate, false); + testNodeType = repoTypeManager.registerNodeType(ntTemplate); } @Test @@ -156,7 +156,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.setName(TEST_TYPE_NAME); ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"}); - JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate, false); + JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate); assertThat(testNodeType.getName(), is(TEST_TYPE_NAME)); JcrNodeType nodeTypeFromRepo = repoTypeManager.getNodeType(testTypeName); @@ -175,7 +175,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate2.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME}); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -188,7 +188,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate2.setName(TEST_TYPE_NAME2); ntTemplate2.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME}); - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate2, ntTemplate}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate2, ntTemplate})); } @Test @@ -202,7 +202,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -225,7 +225,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop3); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -240,7 +240,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -255,7 +255,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -271,7 +271,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -287,7 +287,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -302,7 +302,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -318,7 +318,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -345,7 +345,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -360,7 +360,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -375,7 +375,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -389,7 +389,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -403,7 +403,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -417,7 +417,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -455,7 +455,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -493,7 +493,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -531,7 +531,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -569,7 +569,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -603,7 +603,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME, nodeBTemplate.getName()}); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -632,7 +632,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { nodeBTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -661,7 +661,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { nodeBTemplate.getPropertyDefinitionTemplates().add(prop); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test @@ -690,7 +690,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { nodeBTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } @Test( expected = InvalidNodeTypeDefinitionException.class ) @@ -719,7 +719,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { nodeBTemplate.getNodeDefinitionTemplates().add(child); List templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate}); - compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false)); + compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates)); } /* @@ -756,7 +756,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(childNode); try { - repoTypeManager.registerNodeType(ntTemplate, false); + repoTypeManager.registerNodeType(ntTemplate); } catch (Exception ex) { fail(ex.getMessage()); } @@ -773,7 +773,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(childNode); try { - repoTypeManager.registerNodeType(ntTemplate, false); + repoTypeManager.registerNodeType(ntTemplate); } catch (Exception ex) { fail(ex.getMessage()); } @@ -802,7 +802,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate2.getNodeDefinitionTemplates().add(childNode2); try { - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2})); } catch (Exception ex) { fail(ex.getMessage()); } @@ -829,7 +829,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(childNode); // And register it ... - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate})); } @FixFor( "MODE-826" ) @@ -846,7 +846,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(propertyDefn); // And register it ... - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate})); } @FixFor( "MODE-826" ) @@ -864,7 +864,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getPropertyDefinitionTemplates().add(propertyDefn); // And register it ... - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate})); } @FixFor( "MODE-826" ) @@ -881,7 +881,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(childNode); // And register it ... - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate})); } @FixFor( "MODE-826" ) @@ -899,7 +899,7 @@ public class TypeRegistrationTest extends AbstractSessionTest { ntTemplate.getNodeDefinitionTemplates().add(childNode); // And register it ... - repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}), false); + repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate})); } private void compareTemplatesToNodeTypes( List templates, Index: modeshape-jcr/src/test/java/org/modeshape/jcr/Vehicles.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/Vehicles.java (revision 2037) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/Vehicles.java (working copy) @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.List; import javax.jcr.PropertyType; import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.nodetype.NodeTypeTemplate; import javax.jcr.version.OnParentVersionAction; import org.modeshape.graph.ExecutionContext; @@ -65,7 +66,7 @@ public class Vehicles { } @SuppressWarnings( "unchecked" ) - public static List getNodeTypes( ExecutionContext context ) throws ConstraintViolationException { + public static List getNodeTypes( ExecutionContext context ) throws ConstraintViolationException { JcrPropertyDefinitionTemplate property; NodeTypeTemplate car = new JcrNodeTypeTemplate(context); @@ -175,6 +176,6 @@ public class Vehicles { property.setRequiredType(PropertyType.LONG); aircraft.getPropertyDefinitionTemplates().add(property); - return Arrays.asList(new NodeTypeTemplate[] {car, aircraft,}); + return Arrays.asList(new NodeTypeDefinition[] {car, aircraft,}); } } Index: modeshape-jcr/src/test/resources/xmlNodeTypeRegistration/custom_nodetypes.xml new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/test/resources/xmlNodeTypeRegistration/custom_nodetypes.xml (working copy) @@ -0,0 +1,114 @@ + + + + + mix:referenceable + nt:hierarchyNode + + + + + + mix:referenceable + nt:hierarchyNode + + + + + + nt:base + + + + + mgnl:metaData + + + + + + mgnl:content + + + + + mix:referenceable + nt:folder + + + + + + nt:base + + + + + mgnl:metaData + + + + + + mgnl:content + + + + + nt:resource + + + + + + mix:referenceable + nt:hierarchyNode + + + + + + nt:base + + + + + mgnl:metaData + + + + + + mgnl:content + + + + + nt:hierarchyNode + + + + + nt:base + + + + \ No newline at end of file Index: modeshape-jcr/src/test/resources/xmlNodeTypeRegistration/magnolia_forum_nodetypes.xml new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/test/resources/xmlNodeTypeRegistration/magnolia_forum_nodetypes.xml (working copy) @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + +]> + + + + + + nt:hierarchyNode + + + + + + + nt:base + mix:versionable + + + + mgnl:messageProperties + + + + + mgnl:message + + + + + + + + + + + + + + + + + + + + nt:base + mix:versionable + + + + mgnl:message + + + + + + + + + + + false + + + + + + + + + nt:base + mix:versionable + + + + mgnl:thread + + + + + + + + + false + + + + + + Index: modeshape-jcr/src/test/resources/xmlNodeTypeRegistration/owfe_nodetypes.xml new file mode 100644 =================================================================== --- /dev/null (revision 2037) +++ modeshape-jcr/src/test/resources/xmlNodeTypeRegistration/owfe_nodetypes.xml (working copy) @@ -0,0 +1,93 @@ + + + + + + + + nt:hierarchyNode + + + + + nt:hierarchyNode + + + + + + nt:hierarchyNode + + + + + nt:hierarchyNode + + + + \ No newline at end of file