DNA SVN: r829 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/io and 7 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-15 18:42:18 -0400 (Wed, 15 Apr 2009)
New Revision: 829
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/
trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphImporter.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/
trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java
Removed:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
trunk/dna-jcr-tck/src/test/java/org/jboss/dna/jcr/InMemoryRepositoryStub.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
Log:
DNA-358 Break the XmlHandler.Destination into an area where it can be reused by other importers
Pulled the Destination interface and the current implementations into a new 'org.jboss.dna.graph.io' package. Move the GraphImporter class and it's test case into the same package.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -50,6 +50,7 @@
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.io.GraphImporter;
import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -1,278 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * 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.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * 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.
- *
- * JBoss DNA 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.jboss.dna.graph;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.List;
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.common.text.TextDecoder;
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.connector.RepositorySource;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.xml.XmlHandler;
-import org.jboss.dna.graph.xml.XmlHandler.Destination;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-/**
- * @author Randall Hauch
- * @author John Verhaeg
- */
-public class GraphImporter {
-
- private final Graph graph;
-
- public GraphImporter( Graph graph ) {
- CheckArg.isNotNull(graph, "graph");
- this.graph = graph;
- }
-
- /**
- * Get the context in which the importer will be executed.
- *
- * @return the execution context; never null
- */
- public ExecutionContext getContext() {
- return this.graph.getContext();
- }
-
- /**
- * The graph that this importer uses.
- *
- * @return the graph; never null
- */
- public Graph getGraph() {
- return graph;
- }
-
- /**
- * Read the content from the supplied URI and import into the repository at the supplied location.
- *
- * @param uri the URI where the importer can read the content that is to be imported
- * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
- * be null
- * @return the batch of requests for creating the graph content that represents the imported content
- * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
- * @throws IOException if there is a problem reading the content
- * @throws SAXException if there is a problem with the SAX Parser
- * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
- * source}
- */
- public Graph.Batch importXml( URI uri,
- Location location ) throws IOException, SAXException, RepositorySourceException {
- return importXml(uri, location, false);
- }
-
- /**
- * Read the content from the supplied URI and import into the repository at the supplied location.
- *
- * @param uri the URI where the importer can read the content that is to be imported
- * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
- * be null
- * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
- * @return the batch of requests for creating the graph content that represents the imported content
- * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
- * @throws IOException if there is a problem reading the content
- * @throws SAXException if there is a problem with the SAX Parser
- * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
- * source}
- */
- public Graph.Batch importXml( URI uri,
- Location location,
- boolean skip ) throws IOException, SAXException, RepositorySourceException {
- CheckArg.isNotNull(uri, "uri");
- CheckArg.isNotNull(location, "location");
- CheckArg.isNotNull(location.getPath(), "location.getPath()");
- InputStream stream = null;
- try {
- stream = uri.toURL().openStream();
- return importXml(stream, location, skip);
- } finally {
- if (stream != null) stream.close();
- }
- }
-
- /**
- * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
- * close the stream.
- *
- * @param stream the stream containing the content to be imported
- * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
- * be null
- * @return the batch of requests for creating the graph content that represents the imported content
- * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
- * @throws IOException if there is a problem reading the content
- * @throws SAXException if there is a problem with the SAX Parser
- * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
- * source}
- */
- public Graph.Batch importXml( InputStream stream,
- Location location ) throws IOException, SAXException, RepositorySourceException {
- return importXml(stream, location, false);
- }
-
- /**
- * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
- * close the stream.
- *
- * @param stream the stream containing the content to be imported
- * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
- * be null
- * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
- * @return the batch of requests for creating the graph content that represents the imported content
- * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
- * @throws IOException if there is a problem reading the content
- * @throws SAXException if there is a problem with the SAX Parser
- * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
- * source}
- */
- public Graph.Batch importXml( InputStream stream,
- Location location,
- boolean skip ) throws IOException, SAXException, RepositorySourceException {
- CheckArg.isNotNull(stream, "uri");
- CheckArg.isNotNull(location, "location");
- CheckArg.isNotNull(location.getPath(), "location.getPath()");
-
- // Create the destination for the XmlHandler ...
- Graph.Batch batch = graph.batch();
- XmlHandler.Destination destination = new CreateOnGraphInBatch(batch);
-
- // Determine where the content is to be placed ...
- Path parentPath = location.getPath();
- Name nameAttribute = JcrLexicon.NAME;
- Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
- Name typeAttributeValue = null;
- NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
- if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
- typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
- }
-
- TextDecoder decoder = null;
- XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
- XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
- typeAttributeValue, scoping);
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.setErrorHandler(handler);
- reader.parse(new InputSource(stream));
- if (stream != null) stream.close();
- return batch;
- }
-
- /**
- * Return an {@link XmlHandler} that can be used to import content directly into the supplied location. The operations
- * resulting from the {@link XmlHandler} operations are batched until the {@link XmlHandler#endDocument()} is called, at which
- * point all enqueued operations are submitted to the graph.
- *
- * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
- * be null
- * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
- * @return the {@link XmlHandler} that can be used to import content
- * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
- */
- public XmlHandler getHandlerForImportingXml( Location location,
- boolean skip ) {
- CheckArg.isNotNull(location, "location");
- CheckArg.isNotNull(location.getPath(), "location.getPath()");
-
- // Create the destination for the XmlHandler ...
- Graph.Batch batch = graph.batch();
- XmlHandler.Destination destination = new SubmitToGraphInBatch(batch);
-
- // Determine where the content is to be placed ...
- Path parentPath = location.getPath();
- Name nameAttribute = JcrLexicon.NAME;
- Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
- Name typeAttributeValue = null;
- NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
- if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
- typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
- }
-
- TextDecoder decoder = null;
- XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
- XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
- typeAttributeValue, scoping);
- return handler;
- }
-
- @NotThreadSafe
- protected static class CreateOnGraphInBatch implements Destination {
- protected final Graph.Batch batch;
-
- protected CreateOnGraphInBatch( Graph.Batch batch ) {
- assert batch != null;
- this.batch = batch;
- }
-
- public ExecutionContext getExecutionContext() {
- return batch.getGraph().getContext();
- }
-
- public void create( Path path,
- List<Property> properties ) {
- assert properties != null;
- if (properties.isEmpty()) {
- batch.create(path).and();
- } else {
- batch.create(path, properties).and();
- }
- }
-
- public void create( Path path,
- Property firstProperty,
- Property... additionalProperties ) {
- if (firstProperty == null) {
- batch.create(path).and();
- } else {
- batch.create(path, firstProperty, additionalProperties).and();
- }
- }
-
- public void submit() {
- }
- }
-
- @NotThreadSafe
- protected final static class SubmitToGraphInBatch extends CreateOnGraphInBatch {
- protected SubmitToGraphInBatch( Graph.Batch batch ) {
- super(batch);
- }
-
- @Override
- public void submit() {
- super.submit();
- batch.execute();
- }
- }
-
-}
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -0,0 +1,73 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA 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.
+ *
+ * JBoss DNA 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.jboss.dna.graph.io;
+
+import java.util.List;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+
+/**
+ * Interface used internally as the destination for the requests. This is used to abstract whether the requests should be
+ * submitted immediately or in a single batch.
+ *
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public interface Destination {
+
+ /**
+ * Obtain the execution context of the destination.
+ *
+ * @return the destination's execution context
+ */
+ public ExecutionContext getExecutionContext();
+
+ /**
+ * Create a node at the supplied path and with the supplied attributes. The path will be absolute.
+ *
+ * @param path the absolute path of the node
+ * @param properties the properties for the node; never null, but may be empty if there are no properties
+ */
+ public void create( Path path,
+ List<Property> properties );
+
+ /**
+ * Create a node at the supplied path and with the supplied attributes. The path will be absolute.
+ *
+ * @param path the absolute path of the node
+ * @param firstProperty the first property
+ * @param additionalProperties the remaining properties for the node
+ */
+ public void create( Path path,
+ Property firstProperty,
+ Property... additionalProperties );
+
+ /**
+ * Signal to this destination that any enqueued create requests should be submitted. Usually this happens at the end of the
+ * document parsing, but an implementer must allow for it to be called multiple times and anytime during parsing.
+ */
+ public void submit();
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -0,0 +1,128 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA 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.
+ *
+ * JBoss DNA 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.jboss.dna.graph.io;
+
+import java.util.List;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Graph.Batch;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+
+/**
+ * A {@link Destination} that makes the changes to a graph via a {@link Batch}.
+ */
+@NotThreadSafe
+public class GraphBatchDestination implements Destination {
+ protected final Graph.Batch batch;
+ protected final boolean ignoreSubmit;
+
+ /**
+ * Create a new instance that will use the specified batch. When {@link #submit()} is called, the batch will be
+ * {@link Batch#execute() executed}.
+ *
+ * @param batch the batch
+ * @throws IllegalArgumentException if the batch is null
+ */
+ public GraphBatchDestination( Graph.Batch batch ) {
+ this(batch, false);
+ }
+
+ /**
+ * Create a new instance that will use the specified batch. If {@code ignoreSubmit} is true, then {@link #submit()} does
+ * nothing (and the batch must be executed}; otherwise, {@link #submit()} immediately calls the {@link Batch#execute()
+ * executed}.
+ *
+ * @param batch the batch
+ * @param ignoreSubmit true if the {@link #submit()} method should be ignored, or false otherwise
+ * @throws IllegalArgumentException if the batch is null
+ */
+ public GraphBatchDestination( Graph.Batch batch,
+ boolean ignoreSubmit ) {
+ assert batch != null;
+ this.batch = batch;
+ this.ignoreSubmit = ignoreSubmit;
+ }
+
+ /**
+ * Return whether this instance is ignoring calls to {@link #submit()}.
+ *
+ * @return ignoreSubmit
+ */
+ public boolean isSubmitIgnored() {
+ return ignoreSubmit;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#getExecutionContext()
+ */
+ public ExecutionContext getExecutionContext() {
+ return batch.getGraph().getContext();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#create(org.jboss.dna.graph.property.Path, java.util.List)
+ */
+ public void create( Path path,
+ List<Property> properties ) {
+ assert properties != null;
+ if (properties.isEmpty()) {
+ batch.create(path).and();
+ } else {
+ batch.create(path, properties).and();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#create(org.jboss.dna.graph.property.Path, org.jboss.dna.graph.property.Property,
+ * org.jboss.dna.graph.property.Property[])
+ */
+ public void create( Path path,
+ Property firstProperty,
+ Property... additionalProperties ) {
+ if (firstProperty == null) {
+ batch.create(path).and();
+ } else {
+ batch.create(path, firstProperty, additionalProperties).and();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#submit()
+ */
+ public void submit() {
+ // Execute only if we're not ignoring submits ...
+ if (!this.ignoreSubmit && !batch.hasExecuted()) batch.execute();
+
+ }
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphImporter.java (from rev 809, trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphImporter.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphImporter.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -0,0 +1,229 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.graph.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import org.jboss.dna.common.text.TextDecoder;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.xml.XmlHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class GraphImporter {
+
+ private final Graph graph;
+
+ public GraphImporter( Graph graph ) {
+ CheckArg.isNotNull(graph, "graph");
+ this.graph = graph;
+ }
+
+ /**
+ * Get the context in which the importer will be executed.
+ *
+ * @return the execution context; never null
+ */
+ public ExecutionContext getContext() {
+ return this.graph.getContext();
+ }
+
+ /**
+ * The graph that this importer uses.
+ *
+ * @return the graph; never null
+ */
+ public Graph getGraph() {
+ return graph;
+ }
+
+ /**
+ * Read the content from the supplied URI and import into the repository at the supplied location.
+ *
+ * @param uri the URI where the importer can read the content that is to be imported
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @return the batch of requests for creating the graph content that represents the imported content
+ * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+ * @throws IOException if there is a problem reading the content
+ * @throws SAXException if there is a problem with the SAX Parser
+ * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+ * source}
+ */
+ public Graph.Batch importXml( URI uri,
+ Location location ) throws IOException, SAXException, RepositorySourceException {
+ return importXml(uri, location, false);
+ }
+
+ /**
+ * Read the content from the supplied URI and import into the repository at the supplied location.
+ *
+ * @param uri the URI where the importer can read the content that is to be imported
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+ * @return the batch of requests for creating the graph content that represents the imported content
+ * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+ * @throws IOException if there is a problem reading the content
+ * @throws SAXException if there is a problem with the SAX Parser
+ * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+ * source}
+ */
+ public Graph.Batch importXml( URI uri,
+ Location location,
+ boolean skip ) throws IOException, SAXException, RepositorySourceException {
+ CheckArg.isNotNull(uri, "uri");
+ CheckArg.isNotNull(location, "location");
+ CheckArg.isNotNull(location.getPath(), "location.getPath()");
+ InputStream stream = null;
+ try {
+ stream = uri.toURL().openStream();
+ return importXml(stream, location, skip);
+ } finally {
+ if (stream != null) stream.close();
+ }
+ }
+
+ /**
+ * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
+ * close the stream.
+ *
+ * @param stream the stream containing the content to be imported
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @return the batch of requests for creating the graph content that represents the imported content
+ * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
+ * @throws IOException if there is a problem reading the content
+ * @throws SAXException if there is a problem with the SAX Parser
+ * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+ * source}
+ */
+ public Graph.Batch importXml( InputStream stream,
+ Location location ) throws IOException, SAXException, RepositorySourceException {
+ return importXml(stream, location, false);
+ }
+
+ /**
+ * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
+ * close the stream.
+ *
+ * @param stream the stream containing the content to be imported
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+ * @return the batch of requests for creating the graph content that represents the imported content
+ * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
+ * @throws IOException if there is a problem reading the content
+ * @throws SAXException if there is a problem with the SAX Parser
+ * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+ * source}
+ */
+ public Graph.Batch importXml( InputStream stream,
+ Location location,
+ boolean skip ) throws IOException, SAXException, RepositorySourceException {
+ CheckArg.isNotNull(stream, "uri");
+ CheckArg.isNotNull(location, "location");
+ CheckArg.isNotNull(location.getPath(), "location.getPath()");
+
+ // Create the destination for the XmlHandler ...
+ Graph.Batch batch = graph.batch();
+ Destination destination = new GraphBatchDestination(batch, true);
+
+ // Determine where the content is to be placed ...
+ Path parentPath = location.getPath();
+ Name nameAttribute = JcrLexicon.NAME;
+ Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
+ Name typeAttributeValue = null;
+ NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
+ if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
+ typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
+ }
+
+ TextDecoder decoder = null;
+ XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
+ XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
+ XMLReader reader = XMLReaderFactory.createXMLReader();
+ reader.setContentHandler(handler);
+ reader.setErrorHandler(handler);
+ reader.parse(new InputSource(stream));
+ if (stream != null) stream.close();
+ return batch;
+ }
+
+ /**
+ * Return an {@link XmlHandler} that can be used to import content directly into the supplied location. The operations
+ * resulting from the {@link XmlHandler} operations are batched until the {@link XmlHandler#endDocument()} is called, at which
+ * point all enqueued operations are submitted to the graph.
+ *
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+ * @return the {@link XmlHandler} that can be used to import content
+ * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
+ */
+ public XmlHandler getHandlerForImportingXml( Location location,
+ boolean skip ) {
+ CheckArg.isNotNull(location, "location");
+ CheckArg.isNotNull(location.getPath(), "location.getPath()");
+
+ // Create the destination for the XmlHandler ...
+ Graph.Batch batch = graph.batch();
+ Destination destination = new GraphBatchDestination(batch, false);
+
+ // Determine where the content is to be placed ...
+ Path parentPath = location.getPath();
+ Name nameAttribute = JcrLexicon.NAME;
+ Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
+ Name typeAttributeValue = null;
+ NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
+ if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
+ typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
+ }
+
+ TextDecoder decoder = null;
+ XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
+ XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
+ return handler;
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphImporter.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -34,6 +34,7 @@
import org.jboss.dna.common.text.XmlNameEncoder;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.io.Destination;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.graph.property.NamespaceRegistry;
@@ -405,46 +406,4 @@
return result;
}
- /**
- * Interface used internally as the destination for the requests. This is used to abstract whether the requests should be
- * submitted immediately or in a single batch.
- *
- * @author Randall Hauch
- */
- @NotThreadSafe
- public static interface Destination {
-
- /**
- * Obtain the execution context of the destination.
- *
- * @return the destination's execution context
- */
- public ExecutionContext getExecutionContext();
-
- /**
- * Create a node at the supplied path and with the supplied attributes. The path will be absolute.
- *
- * @param path the absolute path of the node
- * @param properties the properties for the node; never null, but may be empty if there are no properties
- */
- public void create( Path path,
- List<Property> properties );
-
- /**
- * Create a node at the supplied path and with the supplied attributes. The path will be absolute.
- *
- * @param path the absolute path of the node
- * @param firstProperty the first property
- * @param additionalProperties the remaining properties for the node
- */
- public void create( Path path,
- Property firstProperty,
- Property... additionalProperties );
-
- /**
- * Signal to this destination that any enqueued create requests should be submitted. Usually this happens at the end of
- * the document parsing, but an implementer must allow for it to be called multiple times and anytime during parsing.
- */
- public void submit();
- }
}
Deleted: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -1,186 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * 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.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * 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.
- *
- * JBoss DNA 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.jboss.dna.graph;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.stub;
-import java.io.File;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.transaction.xa.XAResource;
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.connector.RepositoryConnection;
-import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.connector.RepositorySourceListener;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.request.CompositeRequest;
-import org.jboss.dna.graph.request.CreateNodeRequest;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class GraphImporterTest {
-
- private Graph graph;
- private GraphImporter importer;
- private String sourceName;
- private ExecutionContext context;
- private URI xmlContent;
- private MockRepositoryConnection connection;
- private Request lastExecutedRequest;
- private Path destinationPath;
- @Mock
- private RepositoryConnectionFactory sources;
-
- @Before
- public void beforeEach() throws Exception {
- MockitoAnnotations.initMocks(this);
- xmlContent = new File("src/test/resources/repositoryImporterTestData1.xml").toURI();
- context = new ExecutionContext();
- context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
- context.getNamespaceRegistry().register("jcr", "http://www.jcp.org/jcr/1.0");
- context.getNamespaceRegistry().register("nt", "http://www.jcp.org/jcr/nt/1.0");
- sourceName = "sourceA";
- destinationPath = context.getValueFactories().getPathFactory().create("/a/b");
- graph = Graph.create(sourceName, sources, context);
- importer = new GraphImporter(graph);
- connection = new MockRepositoryConnection();
- stub(sources.createConnection(sourceName)).toReturn(connection);
- }
-
- @Test
- public void shouldImportXmlContentAndGenerateTheCorrectCommands() throws Exception {
- System.out.println(xmlContent);
- Graph.Batch batch = importer.importXml(xmlContent, Location.create(destinationPath));
- batch.execute();
- // 'lastExecutedCommand'
- assertThat(lastExecutedRequest, is(instanceOf(CompositeRequest.class)));
- Iterator<Request> iter = ((CompositeRequest)lastExecutedRequest).iterator();
- // assertCreateNode(iter, "/a/b/", "jcr:primaryType={http://www.jboss.org/dna/xml/1.0}document");
- assertCreateNode(iter, "/a/b/dna:system[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
- assertCreateNode(iter, "/a/b/dna:system[1]/dna:sources[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
- assertCreateNode(iter,
- "/a/b/dna:system[1]/dna:sources[1]/sourceA[1]",
- "repositoryName=repositoryA",
- "retryLimit=3",
- "jcr:primaryType={http://www.jboss.org/dna/1.0}xyz",
- "dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
- assertCreateNode(iter,
- "/a/b/dna:system[1]/dna:sources[1]/sourceB[1]",
- "repositoryName=repositoryB",
- "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured",
- "dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
- assertThat(iter.hasNext(), is(false));
- }
-
- public void assertCreateNode( Iterator<Request> iterator,
- String path,
- String... properties ) {
- Request nextCommand = iterator.next();
- assertThat(nextCommand, is(instanceOf(CreateNodeRequest.class)));
- CreateNodeRequest createNode = (CreateNodeRequest)nextCommand;
- Path expectedPath = context.getValueFactories().getPathFactory().create(path);
- Path parentPath = createNode.under().getPath();
- assertThat(parentPath, is(expectedPath.getParent()));
- assertThat(createNode.named(), is(expectedPath.getLastSegment().getName()));
- Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
- for (Property prop : createNode.properties()) {
- propertiesByName.put(prop.getName(), prop);
- }
- for (String propertyStr : properties) {
- if (propertyStr == "any properties") {
- propertiesByName.clear();
- break;
- }
- Matcher matcher = Pattern.compile("([^=]+)=(.*)").matcher(propertyStr);
- if (!matcher.matches()) continue;
- System.out.println("Property: " + propertyStr + " ==> " + matcher);
- Name propertyName = context.getValueFactories().getNameFactory().create(matcher.group(1));
- System.out.println("Property name: " + matcher.group(1));
- String value = matcher.group(2); // doesn't handle multiple values!!
- if (value.trim().length() == 0) value = null;
- Property actual = propertiesByName.remove(propertyName);
- Property expectedProperty = context.getPropertyFactory().create(propertyName, value);
- assertThat("missing property " + propertyName, actual, is(expectedProperty));
- }
- if (!propertiesByName.isEmpty()) {
- System.out.println("Properties for " + path + "\n" + propertiesByName);
- }
- assertThat(propertiesByName.isEmpty(), is(true));
- }
-
- protected class MockRepositoryConnection implements RepositoryConnection {
- public void close() {
- }
-
- @SuppressWarnings( "synthetic-access" )
- public void execute( ExecutionContext context,
- Request request ) throws RepositorySourceException {
- lastExecutedRequest = request;
- if (request instanceof VerifyWorkspaceRequest) {
- VerifyWorkspaceRequest workspaceRequest = (VerifyWorkspaceRequest)request;
- workspaceRequest.setActualRootLocation(Location.create(context.getValueFactories().getPathFactory().createRootPath()));
- workspaceRequest.setActualWorkspaceName("default");
- }
- }
-
- public CachePolicy getDefaultCachePolicy() {
- return null;
- }
-
- @SuppressWarnings( "synthetic-access" )
- public String getSourceName() {
- return sourceName;
- }
-
- public XAResource getXAResource() {
- return null;
- }
-
- public boolean ping( long time,
- TimeUnit unit ) {
- return true;
- }
-
- public void setListener( RepositorySourceListener listener ) {
- }
- }
-
-}
Copied: trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java (from rev 776, trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java)
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -0,0 +1,192 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.graph.io;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.stub;
+import java.io.File;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.transaction.xa.XAResource;
+import org.jboss.dna.graph.DnaLexicon;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.RepositorySourceListener;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.request.CompositeRequest;
+import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class GraphImporterTest {
+
+ private Graph graph;
+ private GraphImporter importer;
+ private String sourceName;
+ private ExecutionContext context;
+ private URI xmlContent;
+ private MockRepositoryConnection connection;
+ private Request lastExecutedRequest;
+ private Path destinationPath;
+ @Mock
+ private RepositoryConnectionFactory sources;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ xmlContent = new File("src/test/resources/repositoryImporterTestData1.xml").toURI();
+ context = new ExecutionContext();
+ context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register("jcr", "http://www.jcp.org/jcr/1.0");
+ context.getNamespaceRegistry().register("nt", "http://www.jcp.org/jcr/nt/1.0");
+ sourceName = "sourceA";
+ destinationPath = context.getValueFactories().getPathFactory().create("/a/b");
+ graph = Graph.create(sourceName, sources, context);
+ importer = new GraphImporter(graph);
+ connection = new MockRepositoryConnection();
+ stub(sources.createConnection(sourceName)).toReturn(connection);
+ }
+
+ @Test
+ public void shouldImportXmlContentAndGenerateTheCorrectCommands() throws Exception {
+ System.out.println(xmlContent);
+ Graph.Batch batch = importer.importXml(xmlContent, Location.create(destinationPath));
+ batch.execute();
+ // 'lastExecutedCommand'
+ assertThat(lastExecutedRequest, is(instanceOf(CompositeRequest.class)));
+ Iterator<Request> iter = ((CompositeRequest)lastExecutedRequest).iterator();
+ // assertCreateNode(iter, "/a/b/", "jcr:primaryType={http://www.jboss.org/dna/xml/1.0}document");
+ assertCreateNode(iter, "/a/b/dna:system[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
+ assertCreateNode(iter, "/a/b/dna:system[1]/dna:sources[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
+ assertCreateNode(iter,
+ "/a/b/dna:system[1]/dna:sources[1]/sourceA[1]",
+ "repositoryName=repositoryA",
+ "retryLimit=3",
+ "jcr:primaryType={http://www.jboss.org/dna/1.0}xyz",
+ "dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
+ assertCreateNode(iter,
+ "/a/b/dna:system[1]/dna:sources[1]/sourceB[1]",
+ "repositoryName=repositoryB",
+ "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured",
+ "dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ public void assertCreateNode( Iterator<Request> iterator,
+ String path,
+ String... properties ) {
+ Request nextCommand = iterator.next();
+ assertThat(nextCommand, is(instanceOf(CreateNodeRequest.class)));
+ CreateNodeRequest createNode = (CreateNodeRequest)nextCommand;
+ Path expectedPath = context.getValueFactories().getPathFactory().create(path);
+ Path parentPath = createNode.under().getPath();
+ assertThat(parentPath, is(expectedPath.getParent()));
+ assertThat(createNode.named(), is(expectedPath.getLastSegment().getName()));
+ Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
+ for (Property prop : createNode.properties()) {
+ propertiesByName.put(prop.getName(), prop);
+ }
+ for (String propertyStr : properties) {
+ if (propertyStr == "any properties") {
+ propertiesByName.clear();
+ break;
+ }
+ Matcher matcher = Pattern.compile("([^=]+)=(.*)").matcher(propertyStr);
+ if (!matcher.matches()) continue;
+ System.out.println("Property: " + propertyStr + " ==> " + matcher);
+ Name propertyName = context.getValueFactories().getNameFactory().create(matcher.group(1));
+ System.out.println("Property name: " + matcher.group(1));
+ String value = matcher.group(2); // doesn't handle multiple values!!
+ if (value.trim().length() == 0) value = null;
+ Property actual = propertiesByName.remove(propertyName);
+ Property expectedProperty = context.getPropertyFactory().create(propertyName, value);
+ assertThat("missing property " + propertyName, actual, is(expectedProperty));
+ }
+ if (!propertiesByName.isEmpty()) {
+ System.out.println("Properties for " + path + "\n" + propertiesByName);
+ }
+ assertThat(propertiesByName.isEmpty(), is(true));
+ }
+
+ protected class MockRepositoryConnection implements RepositoryConnection {
+ public void close() {
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public void execute( ExecutionContext context,
+ Request request ) throws RepositorySourceException {
+ lastExecutedRequest = request;
+ if (request instanceof VerifyWorkspaceRequest) {
+ VerifyWorkspaceRequest workspaceRequest = (VerifyWorkspaceRequest)request;
+ workspaceRequest.setActualRootLocation(Location.create(context.getValueFactories()
+ .getPathFactory()
+ .createRootPath()));
+ workspaceRequest.setActualWorkspaceName("default");
+ }
+ }
+
+ public CachePolicy getDefaultCachePolicy() {
+ return null;
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ public boolean ping( long time,
+ TimeUnit unit ) {
+ return true;
+ }
+
+ public void setListener( RepositorySourceListener listener ) {
+ }
+ }
+
+}
Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -40,6 +40,7 @@
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.io.Destination;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
@@ -62,7 +63,7 @@
private XmlHandler handler;
private ExecutionContext context;
- private XmlHandler.Destination destination;
+ private Destination destination;
private boolean skipRootElement = false;
private Path parentPath;
private TextDecoder decoder;
@@ -432,7 +433,7 @@
}
}
- protected class RecordingDestination implements XmlHandler.Destination {
+ protected class RecordingDestination implements Destination {
private final LinkedList<CreateNodeRequest> requests = new LinkedList<CreateNodeRequest>();
private final String workspace = "Recording Workspace";
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -46,11 +46,11 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.GraphImporter;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.io.GraphImporter;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -72,12 +72,12 @@
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.GraphImporter;
import org.jboss.dna.graph.JcrNtLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connector.RepositoryConnection;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.io.GraphImporter;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.jcr.JcrRepository.Options;
Modified: trunk/dna-jcr-tck/src/test/java/org/jboss/dna/jcr/InMemoryRepositoryStub.java
===================================================================
--- trunk/dna-jcr-tck/src/test/java/org/jboss/dna/jcr/InMemoryRepositoryStub.java 2009-04-15 14:28:30 UTC (rev 828)
+++ trunk/dna-jcr-tck/src/test/java/org/jboss/dna/jcr/InMemoryRepositoryStub.java 2009-04-15 22:42:18 UTC (rev 829)
@@ -36,12 +36,12 @@
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.GraphImporter;
import org.jboss.dna.graph.JcrNtLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connector.RepositoryConnection;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.io.GraphImporter;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.jcr.JcrRepository.Options;
17 years
DNA SVN: r828 - in trunk/dna-jcr/src: test/java/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-15 10:28:30 -0400 (Wed, 15 Apr 2009)
New Revision: 828
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
Log:
DNA-355 Wrong Exception Thrown When Creating Reference Value from Non-Referenceable Node
Applied the patch, which corrects JcrSession.getValueFactories.createValue(Node) witto throw a RepositoryException (rather than an UnsupportedRepositoryOperationException) when a non-referenceable node is given as an argument, and which modifies some unit tests as needed.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-15 14:14:33 UTC (rev 827)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-15 14:28:30 UTC (rev 828)
@@ -462,6 +462,9 @@
}
public Value createValue( Node value ) throws RepositoryException {
+ if (!value.isNodeType(JcrMixLexicon.REFERENCEABLE.getString(JcrSession.this.namespaces()))) {
+ throw new RepositoryException();
+ }
String uuid = valueFactories.getStringFactory().create(value.getUUID());
return new JcrValue(valueFactories, sessionCache, PropertyType.REFERENCE, uuid);
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-04-15 14:14:33 UTC (rev 827)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-04-15 14:28:30 UTC (rev 828)
@@ -336,11 +336,20 @@
assertThat(factory.createValue(0L), notNullValue());
Node node = Mockito.mock(Node.class);
stub(node.getUUID()).toReturn(UUID.randomUUID().toString());
+ stub(node.isNodeType("mix:referenceable")).toReturn(true);
assertThat(factory.createValue(node), notNullValue());
assertThat(factory.createValue(""), notNullValue());
assertThat(factory.createValue("", PropertyType.BINARY), notNullValue());
}
+ @Test (expected=RepositoryException.class)
+ public void shouldNotCreateValueForNonReferenceableNode() throws Exception {
+ ValueFactory factory = session.getValueFactory();
+ Node node = Mockito.mock(Node.class);
+ stub(node.getUUID()).toReturn(UUID.randomUUID().toString());
+ factory.createValue(node);
+ }
+
@Test
public void shouldNotHavePendingChanges() throws Exception {
assertThat(session.hasPendingChanges(), is(false));
17 years
DNA SVN: r827 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/request and 1 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-15 10:14:33 -0400 (Wed, 15 Apr 2009)
New Revision: 827
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
Log:
DNA-354 JcrSession.hasPendingChanges Is Not Implemented
Previous changes that were made in addition to the patch did not properly implement the hasPendingChanges method. When doing this, it was discovered that SessionCache was incorrectly creating it's Graph.Batch instance to not use the SessionCache's request builder (which used the cache's list of requests, allowing SessionCache.save(UUID) to play with the pending requests to save only those that affect the branch below the supplied UUID).
This commit corrects the implementation, and all tests now pass.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-15 12:50:45 UTC (rev 826)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-15 14:14:33 UTC (rev 827)
@@ -1899,7 +1899,7 @@
* @see Results
*/
public Batch batch() {
- return new Batch(null);
+ return new Batch(new BatchRequestBuilder());
}
/**
@@ -1933,7 +1933,8 @@
protected boolean executed = false;
/*package*/Batch( BatchRequestBuilder builder ) {
- this.requestQueue = builder != null ? builder : new BatchRequestBuilder();
+ assert builder != null;
+ this.requestQueue = builder;
this.workspaceName = Graph.this.getCurrentWorkspaceName();
this.nextRequests = new BatchConjunction() {
public Batch and() {
@@ -1961,7 +1962,7 @@
* @return true if there are some requests in this batch that need to be executed, or false execution is not required
*/
public boolean isExecuteRequired() {
- return !executed || requestQueue.hasRequests();
+ return !executed && requestQueue.hasRequests();
}
/**
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-04-15 12:50:45 UTC (rev 826)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-04-15 14:14:33 UTC (rev 827)
@@ -72,6 +72,7 @@
if (pendingRequest != null) {
// There's a pending request, we need to build it ...
add(pendingRequest.toRequest());
+ pendingRequest = null;
}
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-15 12:50:45 UTC (rev 826)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-15 14:14:33 UTC (rev 827)
@@ -186,7 +186,7 @@
// Create the batch operations ...
this.requests = new LinkedList<Request>();
this.requestBuilder = new BatchRequestBuilder(this.requests);
- this.operations = this.store.batch();
+ this.operations = this.store.batch(this.requestBuilder);
}
JcrSession session() {
17 years
DNA SVN: r826 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-15 08:50:45 -0400 (Wed, 15 Apr 2009)
New Revision: 826
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
Log:
DNA-354 JcrSession.hasPendingChanges Is Not Implemented
Applied the patch (with changes) that implements this method by checking the SessionCache for unsaved (pending) changes. The patch had checked the 'changes' map to determine whether there were changes, but this misses deletes. Added a method to SessionCache that determines whether there are any pending changes, and implemented this method by checking whether there are any pending operations.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-15 12:35:50 UTC (rev 825)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-15 12:50:45 UTC (rev 826)
@@ -571,11 +571,10 @@
/**
* {@inheritDoc}
*
- * @return false
* @see javax.jcr.Session#hasPendingChanges()
*/
public boolean hasPendingChanges() {
- return false;
+ return cache.hasPendingChanges();
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-15 12:35:50 UTC (rev 825)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-15 12:50:45 UTC (rev 826)
@@ -218,6 +218,15 @@
}
/**
+ * Returns whether the session cache has any pending changes that need to be executed.
+ *
+ * @return true if there are pending changes, or false if there is currently no changes
+ */
+ boolean hasPendingChanges() {
+ return operations.isExecuteRequired();
+ }
+
+ /**
* Save any changes that have been accumulated by this session.
*
* @throws RepositoryException if any error resulting while saving the changes to the repository
@@ -785,8 +794,8 @@
if (!definition.getId().equals(node.getDefinitionId())) {
// The node definition changed, so try to set the property ...
try {
- JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING,
- definition.getId().getString());
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, definition.getId()
+ .getString());
setProperty(DnaLexicon.NODE_DEFINITON, value);
} catch (ConstraintViolationException e) {
// We can't set this property on the node (according to the node definition).
@@ -886,7 +895,7 @@
if (desiredUuid == null) {
desiredUuid = UUID.randomUUID();
}
-
+
// We know that this property is single-valued
JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, desiredUuid.toString());
PropertyDefinition propertyDefinition = nodeTypes().findPropertyDefinition(primaryTypeName,
@@ -898,7 +907,8 @@
PropertyId propId = new PropertyId(desiredUuid, JcrLexicon.UUID);
JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
org.jboss.dna.graph.property.Property uuidProperty = propertyFactory.create(JcrLexicon.UUID, desiredUuid);
- PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), PropertyType.STRING, uuidProperty, defn.isMultiple());
+ PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), PropertyType.STRING, uuidProperty,
+ defn.isMultiple());
properties.put(JcrLexicon.UUID, propInfo);
}
@@ -936,7 +946,10 @@
// ---------------------------------------
// Now record the changes to the store ...
// ---------------------------------------
- Graph.Create<Graph.Batch> create = operations.createUnder(currentLocation).nodeNamed(name).with(desiredUuid).with(primaryTypeProp);
+ Graph.Create<Graph.Batch> create = operations.createUnder(currentLocation)
+ .nodeNamed(name)
+ .with(desiredUuid)
+ .with(primaryTypeProp);
if (nodeDefnDefn != null) {
create = create.with(nodeDefinitionProp);
}
17 years
DNA SVN: r825 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-15 08:35:50 -0400 (Wed, 15 Apr 2009)
New Revision: 825
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSystemViewExporter.java
Log:
DNA-353 JcrSession.exportSystemView Does Not Handle skipBinary = true Properly
Applied the patch that corrects the behavior of JcrSession.exportSystemView.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSystemViewExporter.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSystemViewExporter.java 2009-04-15 12:31:49 UTC (rev 824)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSystemViewExporter.java 2009-04-15 12:35:50 UTC (rev 825)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.jcr;
import java.io.IOException;
@@ -80,7 +103,7 @@
Property specialProperty = ((AbstractJcrNode)node).getProperty(specialPropertyName);
if (specialProperty != null) {
- emitProperty(specialProperty, contentHandler);
+ emitProperty(specialProperty, contentHandler, skipBinary);
}
}
@@ -119,11 +142,7 @@
return;
}
- if (skipBinary && PropertyType.BINARY == prop.getType()) {
- return;
- }
-
- emitProperty(property, contentHandler);
+ emitProperty(property, contentHandler, skipBinary);
}
/**
@@ -131,11 +150,13 @@
*
* @param property the property to be exported
* @param contentHandler the SAX content handler for which SAX events will be invoked as the XML document is created.
+ * @param skipBinary if <code>true</code>, indicates that binary properties should not be exported
* @throws SAXException if an exception occurs during generation of the XML document
* @throws RepositoryException if an exception occurs accessing the content repository
*/
private void emitProperty( Property property,
- ContentHandler contentHandler ) throws RepositoryException, SAXException {
+ ContentHandler contentHandler,
+ boolean skipBinary ) throws RepositoryException, SAXException {
assert property instanceof AbstractJcrProperty : "Illegal attempt to use " + getClass().getName()
+ " on non-DNA property";
@@ -164,10 +185,10 @@
Value[] values = prop.getValues();
for (int i = 0; i < values.length; i++) {
- emitValue(values[i], contentHandler, property.getType());
+ emitValue(values[i], contentHandler, property.getType(), skipBinary);
}
} else {
- emitValue(property.getValue(), contentHandler, property.getType());
+ emitValue(property.getValue(), contentHandler, property.getType(), skipBinary);
}
// end the sv:property element
@@ -180,30 +201,35 @@
* @param value the value to be exported
* @param contentHandler the SAX content handler for which SAX events will be invoked as the XML document is created.
* @param propertyType the {@link PropertyType} for the given value
+ * @param skipBinary if <code>true</code>, indicates that binary properties should not be exported
* @throws SAXException if an exception occurs during generation of the XML document
* @throws RepositoryException if an exception occurs accessing the content repository
*/
private void emitValue( Value value,
ContentHandler contentHandler,
- int propertyType ) throws RepositoryException, SAXException {
+ int propertyType,
+ boolean skipBinary ) throws RepositoryException, SAXException {
if (PropertyType.BINARY == propertyType) {
startElement(contentHandler, JcrSvLexicon.VALUE, null);
- byte[] bytes = new byte[BASE_64_BUFFER_SIZE];
- int len;
+ // Per section 6.5 of the 1.0.1 spec, we need to emit one empty-value tag for each value if the property is
+ // multi-valued and skipBinary is true
+ if (!skipBinary) {
+ byte[] bytes = new byte[BASE_64_BUFFER_SIZE];
+ int len;
- try {
- InputStream stream = new Base64.InputStream(value.getStream(), Base64.ENCODE | Base64.URL_SAFE
- | Base64.DONT_BREAK_LINES);
+ try {
+ InputStream stream = new Base64.InputStream(value.getStream(), Base64.ENCODE | Base64.URL_SAFE
+ | Base64.DONT_BREAK_LINES);
- while (-1 != (len = stream.read(bytes))) {
- contentHandler.characters(new String(bytes, 0, len).toCharArray(), 0, len);
+ while (-1 != (len = stream.read(bytes))) {
+ contentHandler.characters(new String(bytes, 0, len).toCharArray(), 0, len);
+ }
+ } catch (IOException ioe) {
+ throw new RepositoryException(ioe);
}
- } catch (IOException ioe) {
- throw new RepositoryException(ioe);
}
-
endElement(contentHandler, JcrSvLexicon.VALUE);
} else {
String s = value.getString();
17 years
DNA SVN: r824 - in trunk/dna-jcr/src: test/java/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-15 08:31:49 -0400 (Wed, 15 Apr 2009)
New Revision: 824
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
Log:
DNA-352 Version Tests in SerializationTest Fail Due to TCK Bug
Applied the patch that removes the version-related built-in node types, modifies the canAddMixin(...) method, modifies test that had coincidental dependency on one of the version built-in types. This change was needed because of what appears to be incorrect behavior in the TCK unit tests. For more details, see DNA-352.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-14 20:06:32 UTC (rev 823)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-15 12:31:49 UTC (rev 824)
@@ -615,6 +615,17 @@
CheckArg.isNotNull(mixinName, "mixinName");
CheckArg.isNotZeroLength(mixinName, "mixinName");
+ /*
+ * Special workaround for SeralizationTest (and others) in JR TCK that incorrectly test whether a repository supports
+ * versioning by trying to add mix:versionable to a node. The 1.0.1 says in section 4.11 that:
+ * "A node is versionable if and only if it has been assigned the mixin type mix:versionable,
+ * otherwise it is nonversionable. Repositories that do not support versioning will simply not
+ * provide this mixin type, whereas repositories that do support versioning must provide it."
+ */
+ if (JcrMixLexicon.VERSIONABLE.getString(namespaces()).equals(mixinName)) {
+ return false;
+ }
+
JcrNodeType mixinCandidateType = cache.nodeTypes().getNodeType(mixinName);
if (this.isLocked()) {
@@ -1354,7 +1365,7 @@
* @throws UnsupportedRepositoryOperationException always
* @see javax.jcr.Node#checkout()
*/
- public final void checkout() throws UnsupportedRepositoryOperationException {
+ public final void checkout() throws UnsupportedRepositoryOperationException {
throw new UnsupportedRepositoryOperationException();
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java 2009-04-14 20:06:32 UTC (rev 823)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java 2009-04-15 12:31:49 UTC (rev 824)
@@ -31,8 +31,6 @@
import javax.jcr.Value;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.basic.BasicName;
/**
* {@link JcrNodeTypeSource} that provides built-in node types per the 1.0 specification.
@@ -56,7 +54,7 @@
/*
* These values get created without a session cache, as they aren't tied to any particular session.
*/
- Value trueValue = new JcrValue(context.getValueFactories(), null, PropertyType.BOOLEAN, Boolean.TRUE);
+ // Value trueValue = new JcrValue(context.getValueFactories(), null, PropertyType.BOOLEAN, Boolean.TRUE);
Value ntBaseValue = new JcrValue(context.getValueFactories(), null, PropertyType.NAME, JcrNtLexicon.BASE);
// Stubbing in child node and property definitions for now
@@ -458,118 +456,119 @@
PropertyType.UNDEFINED, NO_CONSTRAINTS, true),}),
NOT_MIXIN, ORDERABLE_CHILD_NODES);
- JcrNodeType version = new JcrNodeType(
- context,
- NO_NODE_TYPE_MANAGER,
- JcrNtLexicon.VERSION,
- Arrays.asList(new JcrNodeType[] {base, referenceable}),
- NO_PRIMARY_ITEM_NAME,
- Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
- context,
- null,
- JcrLexicon.FROZEN_NODE,
- OnParentVersionBehavior.ABORT.getJcrValue(),
- false,
- false,
- true,
- false,
- null,
- new JcrNodeType[] {frozenNode}),}),
- Arrays.asList(new JcrPropertyDefinition[] {
- new JcrPropertyDefinition(context, null, JcrLexicon.CREATED,
- OnParentVersionBehavior.ABORT.getJcrValue(), true,
- true, true, NO_DEFAULT_VALUES, PropertyType.DATE,
- NO_CONSTRAINTS, false),
- new JcrPropertyDefinition(context, null, JcrLexicon.PREDECESSORS,
- OnParentVersionBehavior.ABORT.getJcrValue(), false,
- false, true, NO_DEFAULT_VALUES,
- PropertyType.REFERENCE, NO_CONSTRAINTS, true),
- new JcrPropertyDefinition(context, null, JcrLexicon.SUCCESSORS,
- OnParentVersionBehavior.ABORT.getJcrValue(), false,
- false, true, NO_DEFAULT_VALUES,
- PropertyType.REFERENCE, NO_CONSTRAINTS, true),}),
- NOT_MIXIN, UNORDERABLE_CHILD_NODES);
+ // JcrNodeType version = new JcrNodeType(
+ // context,
+ // NO_NODE_TYPE_MANAGER,
+ // JcrNtLexicon.VERSION,
+ // Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ // NO_PRIMARY_ITEM_NAME,
+ // Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ // context,
+ // null,
+ // JcrLexicon.FROZEN_NODE,
+ // OnParentVersionBehavior.ABORT.getJcrValue(),
+ // false,
+ // false,
+ // true,
+ // false,
+ // null,
+ // new JcrNodeType[] {frozenNode}),}),
+ // Arrays.asList(new JcrPropertyDefinition[] {
+ // new JcrPropertyDefinition(context, null, JcrLexicon.CREATED,
+ // OnParentVersionBehavior.ABORT.getJcrValue(), true,
+ // true, true, NO_DEFAULT_VALUES, PropertyType.DATE,
+ // NO_CONSTRAINTS, false),
+ // new JcrPropertyDefinition(context, null, JcrLexicon.PREDECESSORS,
+ // OnParentVersionBehavior.ABORT.getJcrValue(), false,
+ // false, true, NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE, NO_CONSTRAINTS, true),
+ // new JcrPropertyDefinition(context, null, JcrLexicon.SUCCESSORS,
+ // OnParentVersionBehavior.ABORT.getJcrValue(), false,
+ // false, true, NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE, NO_CONSTRAINTS, true),}),
+ // NOT_MIXIN, UNORDERABLE_CHILD_NODES);
+ //
+ // JcrNodeType versionLabels = new JcrNodeType(
+ // context,
+ // NO_NODE_TYPE_MANAGER,
+ // JcrNtLexicon.VERSION_LABELS,
+ // Arrays.asList(new JcrNodeType[] {base}),
+ // NO_PRIMARY_ITEM_NAME,
+ // NO_CHILD_NODES,
+ // Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ // context,
+ // null,
+ // ALL_NODES,
+ // OnParentVersionBehavior.ABORT.getJcrValue(),
+ // false,
+ // false,
+ // true,
+ // NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE,
+ // NO_CONSTRAINTS,
+ // false),}),
+ // NOT_MIXIN, UNORDERABLE_CHILD_NODES);
+ //
+ // JcrNodeType versionHistory = new JcrNodeType(
+ // context,
+ // NO_NODE_TYPE_MANAGER,
+ // JcrNtLexicon.VERSION_HISTORY,
+ // Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ // NO_PRIMARY_ITEM_NAME,
+ // Arrays.asList(new JcrNodeDefinition[] {
+ // new JcrNodeDefinition(context, null, JcrLexicon.ROOT_VERSION,
+ // OnParentVersionBehavior.ABORT.getJcrValue(), true,
+ // true, true, false, JcrNtLexicon.VERSION,
+ // new JcrNodeType[] {version}),
+ // new JcrNodeDefinition(context, null, JcrLexicon.VERSION_LABELS,
+ // OnParentVersionBehavior.ABORT.getJcrValue(), true,
+ // true, true, false, JcrNtLexicon.VERSION_LABELS,
+ // new JcrNodeType[] {versionLabels}),
+ // new JcrNodeDefinition(context, null, ALL_NODES,
+ // OnParentVersionBehavior.ABORT.getJcrValue(),
+ // false, false, true, false, JcrNtLexicon.VERSION,
+ // new JcrNodeType[] {version}),}),
+ // Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ // context,
+ // null,
+ // JcrLexicon.VERSIONABLE_UUID,
+ // OnParentVersionBehavior.ABORT.getJcrValue(),
+ // true,
+ // true,
+ // true,
+ // NO_DEFAULT_VALUES,
+ // PropertyType.STRING,
+ // NO_CONSTRAINTS,
+ // false),}),
+ // NOT_MIXIN, UNORDERABLE_CHILD_NODES);
+ //
+ // Name CHILD_VERSION_HISTORY = new BasicName(JcrLexicon.Namespace.URI, "childVersionHistory");
+ // JcrNodeType versionedChild = new JcrNodeType(
+ // context,
+ // NO_NODE_TYPE_MANAGER,
+ // JcrNtLexicon.VERSIONED_CHILD,
+ // Arrays.asList(new JcrNodeType[] {base}),
+ // NO_PRIMARY_ITEM_NAME,
+ // NO_CHILD_NODES,
+ // Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ // context,
+ // null,
+ // CHILD_VERSION_HISTORY,
+ // OnParentVersionBehavior.ABORT.getJcrValue(),
+ // true,
+ // true,
+ // true,
+ // NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE,
+ // NO_CONSTRAINTS,
+ // false),}),
+ // NOT_MIXIN, UNORDERABLE_CHILD_NODES);
- JcrNodeType versionLabels = new JcrNodeType(
- context,
- NO_NODE_TYPE_MANAGER,
- JcrNtLexicon.VERSION_LABELS,
- Arrays.asList(new JcrNodeType[] {base}),
- NO_PRIMARY_ITEM_NAME,
- NO_CHILD_NODES,
- Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
- context,
- null,
- ALL_NODES,
- OnParentVersionBehavior.ABORT.getJcrValue(),
- false,
- false,
- true,
- NO_DEFAULT_VALUES,
- PropertyType.REFERENCE,
- NO_CONSTRAINTS,
- false),}),
- NOT_MIXIN, UNORDERABLE_CHILD_NODES);
+ // Disabling version-related types until DNA supports versioning, as per section 4.11 of the 1.0.1 specification
+ nodeTypes.addAll(Arrays.asList(new JcrNodeType[] {base, unstructured, childNodeDefinition, file, folder, frozenNode,
+ hierarchyNode, linkedFile, nodeType, propertyDefinition, query, resource, nodeType /*, version, versionHistory,
+ versionLabels, versionedChild */}));
- JcrNodeType versionHistory = new JcrNodeType(
- context,
- NO_NODE_TYPE_MANAGER,
- JcrNtLexicon.VERSION_HISTORY,
- Arrays.asList(new JcrNodeType[] {base, referenceable}),
- NO_PRIMARY_ITEM_NAME,
- Arrays.asList(new JcrNodeDefinition[] {
- new JcrNodeDefinition(context, null, JcrLexicon.ROOT_VERSION,
- OnParentVersionBehavior.ABORT.getJcrValue(), true,
- true, true, false, JcrNtLexicon.VERSION,
- new JcrNodeType[] {version}),
- new JcrNodeDefinition(context, null, JcrLexicon.VERSION_LABELS,
- OnParentVersionBehavior.ABORT.getJcrValue(), true,
- true, true, false, JcrNtLexicon.VERSION_LABELS,
- new JcrNodeType[] {versionLabels}),
- new JcrNodeDefinition(context, null, ALL_NODES,
- OnParentVersionBehavior.ABORT.getJcrValue(),
- false, false, true, false, JcrNtLexicon.VERSION,
- new JcrNodeType[] {version}),}),
- Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
- context,
- null,
- JcrLexicon.VERSIONABLE_UUID,
- OnParentVersionBehavior.ABORT.getJcrValue(),
- true,
- true,
- true,
- NO_DEFAULT_VALUES,
- PropertyType.STRING,
- NO_CONSTRAINTS,
- false),}),
- NOT_MIXIN, UNORDERABLE_CHILD_NODES);
-
- Name CHILD_VERSION_HISTORY = new BasicName(JcrLexicon.Namespace.URI, "childVersionHistory");
- JcrNodeType versionedChild = new JcrNodeType(
- context,
- NO_NODE_TYPE_MANAGER,
- JcrNtLexicon.VERSIONED_CHILD,
- Arrays.asList(new JcrNodeType[] {base}),
- NO_PRIMARY_ITEM_NAME,
- NO_CHILD_NODES,
- Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
- context,
- null,
- CHILD_VERSION_HISTORY,
- OnParentVersionBehavior.ABORT.getJcrValue(),
- true,
- true,
- true,
- NO_DEFAULT_VALUES,
- PropertyType.REFERENCE,
- NO_CONSTRAINTS,
- false),}),
- NOT_MIXIN, UNORDERABLE_CHILD_NODES);
-
- nodeTypes.addAll(Arrays.asList(new JcrNodeType[] {base, unstructured, childNodeDefinition, file, folder,
- frozenNode, hierarchyNode, linkedFile, nodeType, propertyDefinition, query, resource, nodeType, version,
- versionHistory, versionLabels, versionedChild}));
-
JcrNodeType lockable = new JcrNodeType(context, NO_NODE_TYPE_MANAGER, JcrMixLexicon.LOCKABLE, NO_SUPERTYPES,
NO_PRIMARY_ITEM_NAME, NO_CHILD_NODES, Arrays.asList(new JcrPropertyDefinition[] {
new JcrPropertyDefinition(context, null, JcrLexicon.LOCK_IS_DEEP,
@@ -582,37 +581,38 @@
NO_CONSTRAINTS, false)}), IS_A_MIXIN,
UNORDERABLE_CHILD_NODES);
- JcrNodeType versionable = new JcrNodeType(
- context,
- NO_NODE_TYPE_MANAGER,
- JcrMixLexicon.VERSIONABLE,
- Arrays.asList(new JcrNodeType[] {referenceable}),
- NO_PRIMARY_ITEM_NAME,
- NO_CHILD_NODES,
- Arrays.asList(new JcrPropertyDefinition[] {
- new JcrPropertyDefinition(context, null, JcrLexicon.BASE_VERSION,
- OnParentVersionBehavior.IGNORE.getJcrValue(),
- false, true, true, NO_DEFAULT_VALUES,
- PropertyType.REFERENCE, NO_CONSTRAINTS, false),
- new JcrPropertyDefinition(context, null, JcrLexicon.IS_CHECKED_OUT,
- OnParentVersionBehavior.IGNORE.getJcrValue(),
- true, true, true, new Value[] {trueValue},
- PropertyType.BOOLEAN, NO_CONSTRAINTS, false),
- new JcrPropertyDefinition(context, null, JcrLexicon.MERGE_FAILED,
- OnParentVersionBehavior.ABORT.getJcrValue(),
- false, false, true, NO_DEFAULT_VALUES,
- PropertyType.REFERENCE, NO_CONSTRAINTS, true),
- new JcrPropertyDefinition(context, null, JcrLexicon.PREDECESSORS,
- OnParentVersionBehavior.COPY.getJcrValue(),
- false, true, true, NO_DEFAULT_VALUES,
- PropertyType.REFERENCE, NO_CONSTRAINTS, true),
- new JcrPropertyDefinition(context, null, JcrLexicon.VERSION_HISTORY,
- OnParentVersionBehavior.COPY.getJcrValue(),
- false, true, true, NO_DEFAULT_VALUES,
- PropertyType.REFERENCE, NO_CONSTRAINTS, false),}),
- IS_A_MIXIN, UNORDERABLE_CHILD_NODES);
+ // JcrNodeType versionable = new JcrNodeType(
+ // context,
+ // NO_NODE_TYPE_MANAGER,
+ // JcrMixLexicon.VERSIONABLE,
+ // Arrays.asList(new JcrNodeType[] {referenceable}),
+ // NO_PRIMARY_ITEM_NAME,
+ // NO_CHILD_NODES,
+ // Arrays.asList(new JcrPropertyDefinition[] {
+ // new JcrPropertyDefinition(context, null, JcrLexicon.BASE_VERSION,
+ // OnParentVersionBehavior.IGNORE.getJcrValue(),
+ // false, true, true, NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE, NO_CONSTRAINTS, false),
+ // new JcrPropertyDefinition(context, null, JcrLexicon.IS_CHECKED_OUT,
+ // OnParentVersionBehavior.IGNORE.getJcrValue(),
+ // true, true, true, new Value[] {trueValue},
+ // PropertyType.BOOLEAN, NO_CONSTRAINTS, false),
+ // new JcrPropertyDefinition(context, null, JcrLexicon.MERGE_FAILED,
+ // OnParentVersionBehavior.ABORT.getJcrValue(),
+ // false, false, true, NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE, NO_CONSTRAINTS, true),
+ // new JcrPropertyDefinition(context, null, JcrLexicon.PREDECESSORS,
+ // OnParentVersionBehavior.COPY.getJcrValue(),
+ // false, true, true, NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE, NO_CONSTRAINTS, true),
+ // new JcrPropertyDefinition(context, null, JcrLexicon.VERSION_HISTORY,
+ // OnParentVersionBehavior.COPY.getJcrValue(),
+ // false, true, true, NO_DEFAULT_VALUES,
+ // PropertyType.REFERENCE, NO_CONSTRAINTS, false),}),
+ // IS_A_MIXIN, UNORDERABLE_CHILD_NODES);
- nodeTypes.addAll(Arrays.asList(new JcrNodeType[] {lockable, referenceable, versionable}));
+ // Removing lockable as per section 4.11 of the JCR 1.0.1 specification
+ nodeTypes.addAll(Arrays.asList(new JcrNodeType[] {lockable, referenceable /*, versionable */}));
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-04-14 20:06:32 UTC (rev 823)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-04-15 12:31:49 UTC (rev 824)
@@ -55,7 +55,6 @@
private JcrNodeType referenceable;
private JcrNodeType unstructured;
private JcrNodeType root;
- private JcrNodeType versionHistory;
private JcrNodeType hierarchyNode;
private JcrNodeType file;
@@ -74,7 +73,6 @@
referenceable = repoTypeManager.getNodeType(JcrMixLexicon.REFERENCEABLE);
unstructured = repoTypeManager.getNodeType(JcrNtLexicon.UNSTRUCTURED);
root = repoTypeManager.getNodeType(DnaLexicon.ROOT);
- versionHistory = repoTypeManager.getNodeType(JcrNtLexicon.VERSION_HISTORY);
hierarchyNode = repoTypeManager.getNodeType(JcrNtLexicon.HIERARCHY_NODE);
file = repoTypeManager.getNodeType(JcrNtLexicon.FILE);
}
@@ -548,12 +546,12 @@
context,
AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
nameFor(TEST_TYPE_NAME),
- Arrays.asList(new JcrNodeType[] {versionHistory}),
+ Arrays.asList(new JcrNodeType[] {file}),
AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
context,
null,
- JcrLexicon.ROOT_VERSION,
+ JcrLexicon.CONTENT,
OnParentVersionBehavior.VERSION.getJcrValue(),
false, false, false, false,
JcrNtLexicon.BASE,
17 years
DNA SVN: r823 - in trunk/dna-jcr/src: test/java/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-14 16:06:32 -0400 (Tue, 14 Apr 2009)
New Revision: 823
Added:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
Log:
DNA-339 JCR Type Registration and Unregistration
Applying the "no key" patch, which removes the Key nested class from JcrNodeDefinition and JcrPropertyDefinition and instead uses the (existing) NodeDefinitionId and PropertyDefinitionId. The patch also adds test cases for type registration.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java 2009-04-14 16:41:54 UTC (rev 822)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java 2009-04-14 20:06:32 UTC (rev 823)
@@ -27,15 +27,11 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Value;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NamespaceRegistry;
/**
* DNA implementation of the {@link NodeDefinition} class.
@@ -212,6 +208,13 @@
defaultPrimaryTypeName, required);
}
+ JcrNodeDefinition with( RepositoryNodeTypeManager nodeTypeManager ) {
+ JcrNodeType[] required = requiredPrimaryTypesByName.values().toArray(new JcrNodeType[requiredPrimaryTypesByName.size()]);
+ return new JcrNodeDefinition(this.context, nodeTypeManager, this.declaringNodeType, name, getOnParentVersion(),
+ isAutoCreated(), isMandatory(), isProtected(), allowsSameNameSiblings(),
+ defaultPrimaryTypeName, required);
+ }
+
/**
* {@inheritDoc}
*
@@ -221,74 +224,4 @@
public String toString() {
return getId().toString();
}
-
- Key getKey(boolean includeTypes) {
- return new Key(this, includeTypes);
- }
-
- /**
- * Internal class that encapsulates composite unique identifier for child node definitions
- */
- class Key {
- String keyString;
-
- Key( Node node,
- NamespaceRegistry registry ) throws Exception {
- StringBuffer buff = new StringBuffer();
-
- try {
- String nodeName = node.getProperty(JcrLexicon.NAME.getString(registry)).getString();
- buff.append(nodeName);
- } catch (PathNotFoundException pnfe) {
- // Ignorable, means name is not set.
- buff.append(JcrNodeType.RESIDUAL_ITEM_NAME);
- }
-
- try {
- Value[] requiredTypes = node.getProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES.getString(registry)).getValues();
-
- for (int i = 0; i < requiredTypes.length; i++) {
- buff.append('_').append(requiredTypes[i].getString());
- }
- } catch (PathNotFoundException pnfe) {
- // No required types. Weird, but not debilitating.
- }
-
- buff.append('_').append(node.getProperty(JcrLexicon.SAME_NAME_SIBLINGS.getString(registry)).getBoolean());
-
- this.keyString = buff.toString();
- }
-
- Key( NodeDefinition def,
- boolean includeTypes ) {
- StringBuffer buff = new StringBuffer();
- buff.append(def.getName());
-
- if (includeTypes) {
- NodeType[] requiredTypes = def.getRequiredPrimaryTypes();
- for (int i = 0; i < requiredTypes.length; i++) {
- buff.append('_').append(requiredTypes[i].getName());
- }
- }
-
- buff.append('_').append(def.allowsSameNameSiblings());
-
- this.keyString = buff.toString();
- }
-
- @Override
- public boolean equals( Object ob ) {
- if (!(ob instanceof Key)) {
- return false;
- }
-
- return keyString.equals(((Key)ob).keyString);
- }
-
- @Override
- public int hashCode() {
- return keyString.hashCode();
- }
- }
-
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-04-14 16:41:54 UTC (rev 822)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-04-14 20:06:32 UTC (rev 823)
@@ -112,6 +112,8 @@
Collection<JcrPropertyDefinition> propertyDefinitions,
boolean mixin,
boolean orderableChildNodes ) {
+ assert context != null;
+
this.context = context;
this.nodeTypeManager = nodeTypeManager;
this.name = name;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-04-14 16:41:54 UTC (rev 822)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-04-14 20:06:32 UTC (rev 823)
@@ -26,7 +26,6 @@
import java.util.UUID;
import java.util.regex.Pattern;
import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
@@ -37,7 +36,6 @@
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
-import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.ValueFactories;
@@ -148,7 +146,7 @@
* @return a new <code>JcrPropertyDefinition</code> that is identical to the current object, but with the given
* <code>context</code>.
*/
- JcrPropertyDefinition with( ExecutionContext context) {
+ JcrPropertyDefinition with( ExecutionContext context ) {
return new JcrPropertyDefinition(context, this.declaringNodeType, this.name, this.getOnParentVersion(),
this.isAutoCreated(), this.isMandatory(), this.isProtected(), this.getDefaultValues(),
this.getRequiredType(), this.getValueConstraints(), this.isMultiple());
@@ -592,12 +590,7 @@
JcrValue jcrValue = (JcrValue)value;
// Need to use the session execution context to handle the remaps
- Name name = jcrValue.sessionCache()
- .session()
- .getExecutionContext()
- .getValueFactories()
- .getNameFactory()
- .create(jcrValue.value());
+ Name name = jcrValue.sessionCache().session().getExecutionContext().getValueFactories().getNameFactory().create(jcrValue.value());
for (int i = 0; i < constraints.length; i++) {
if (constraints[i].equals(name)) {
@@ -689,51 +682,4 @@
return false;
}
}
-
- Key getKey(boolean includeType) {
- return new Key(this, includeType);
- }
-
- /**
- * Internal class that encapsulates composite unique identifier for property definitions
- */
- class Key {
- String keyString;
-
- Key( Node node,
- NamespaceRegistry registry ) throws Exception {
- String propertyName = JcrNodeType.RESIDUAL_ITEM_NAME;
-
- try {
- propertyName = node.getProperty(JcrLexicon.NAME.getString(registry)).getString();
- } catch (PathNotFoundException pnfe) {
- // Ignorable, means name is not set.
- }
- String requiredType = node.getProperty(JcrLexicon.REQUIRED_TYPE.getString(registry)).getString();
- boolean allowsMultiple = node.getProperty(JcrLexicon.MULTIPLE.getString(registry)).getBoolean();
-
- this.keyString = propertyName + "-" + requiredType + "-" + allowsMultiple;
- }
-
- Key( PropertyDefinition def, boolean includeType ) {
- String requiredType = PropertyType.nameFromValue(def.getRequiredType());
-
- this.keyString = def.getName() + (includeType ? "-" + requiredType : "") + "-" + def.isMultiple();
- }
-
- @Override
- public boolean equals( Object ob ) {
- if (!(ob instanceof Key)) {
- return false;
- }
-
- return keyString.equals(((Key)ob).keyString);
- }
-
- @Override
- public int hashCode() {
- return keyString.hashCode();
- }
- }
-
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-04-14 16:41:54 UTC (rev 822)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-04-14 20:06:32 UTC (rev 823)
@@ -92,7 +92,8 @@
*/
private enum NodeCardinality {
NO_SAME_NAME_SIBLINGS,
- SAME_NAME_SIBLINGS
+ SAME_NAME_SIBLINGS,
+ ANY
}
RepositoryNodeTypeManager( ExecutionContext context,
@@ -663,11 +664,14 @@
switch (typesToCheck) {
case NO_SAME_NAME_SIBLINGS:
- nodeDefs = typeName.allChildNodeDefinitions(childNodeName);
+ nodeDefs = typeName.allChildNodeDefinitions(childNodeName, false);
break;
case SAME_NAME_SIBLINGS:
nodeDefs = typeName.allChildNodeDefinitions(childNodeName, true);
break;
+ case ANY:
+ nodeDefs = typeName.allChildNodeDefinitions(childNodeName);
+ break;
}
assert nodeDefs != null;
@@ -1045,12 +1049,13 @@
i++;
}
- nodeDefs.add(nodeDef.with(this.context));
+ nodeDefs.add(nodeDef.with(this.context).with(this));
}
JcrNodeType newNodeType = new JcrNodeType(this.context, this, name, supertypes,
nodeType.getInternalPrimaryItemName(), nodeDefs, propertyDefs,
nodeType.isMixin(), nodeType.hasOrderableChildNodes());
+
typesPendingRegistration.add(newNodeType);
}
@@ -1158,11 +1163,14 @@
String nodeName ) throws RepositoryException {
assert supertypes.size() > 0; // This is reasonable now that we default to having a supertype of nt:base
- Map<JcrPropertyDefinition.Key, JcrPropertyDefinition> props = new HashMap<JcrPropertyDefinition.Key, JcrPropertyDefinition>();
+ Map<PropertyDefinitionId, JcrPropertyDefinition> props = new HashMap<PropertyDefinitionId, JcrPropertyDefinition>();
for (JcrNodeType supertype : supertypes) {
for (JcrPropertyDefinition property : supertype.propertyDefinitions()) {
- JcrPropertyDefinition oldProp = props.put(property.getKey(false), property);
+ JcrPropertyDefinition oldProp = props.put(new PropertyDefinitionId(property.getInternalName(),
+ property.getInternalName(),
+ PropertyType.UNDEFINED, property.isMultiple()),
+ property);
if (oldProp != null) {
String oldPropTypeName = oldProp.getDeclaringNodeType().getName();
String propTypeName = property.getDeclaringNodeType().getName();
@@ -1176,11 +1184,13 @@
}
}
- Map<JcrNodeDefinition.Key, JcrNodeDefinition> childNodes = new HashMap<JcrNodeDefinition.Key, JcrNodeDefinition>();
+ Map<NodeDefinitionId, JcrNodeDefinition> childNodes = new HashMap<NodeDefinitionId, JcrNodeDefinition>();
for (JcrNodeType supertype : supertypes) {
for (JcrNodeDefinition childNode : supertype.childNodeDefinitions()) {
- JcrNodeDefinition oldNode = childNodes.put(childNode.getKey(false), childNode);
+ JcrNodeDefinition oldNode = childNodes.put(new NodeDefinitionId(childNode.getInternalName(),
+ childNode.getInternalName(), new Name[0]),
+ childNode);
if (oldNode != null) {
String oldNodeTypeName = oldNode.getDeclaringNodeType().getName();
String childNodeTypeName = childNode.getDeclaringNodeType().getName();
@@ -1273,17 +1283,14 @@
if (node.isAutoCreated() && node.getDefaultPrimaryType() == null) {
throw new RepositoryException(JcrI18n.autocreatedNodesNeedDefaults.text());
}
- if (node.isMandatory() && node.getName() == null) {
+ if (node.isMandatory() && JcrNodeType.RESIDUAL_ITEM_NAME.equals(node.getName())) {
throw new RepositoryException(JcrI18n.residualDefinitionsCannotBeMandatory.text("child nodes"));
}
Name nodeName = context.getValueFactories().getNameFactory().create(node.getName());
nodeName = nodeName == null ? JcrNodeType.RESIDUAL_NAME : nodeName;
- List<JcrNodeDefinition> ancestors = findChildNodeDefinitions(supertypes,
- nodeName,
- node.allowsSameNameSiblings() ? NodeCardinality.SAME_NAME_SIBLINGS : NodeCardinality.NO_SAME_NAME_SIBLINGS,
- pendingTypes);
+ List<JcrNodeDefinition> ancestors = findChildNodeDefinitions(supertypes, nodeName, NodeCardinality.ANY, pendingTypes);
for (JcrNodeDefinition ancestor : ancestors) {
if (ancestor.isProtected()) {
@@ -1353,7 +1360,7 @@
assert supertypes != null;
assert pendingTypes != null;
- if (prop.isMandatory() && !prop.isProtected() && prop.getName() == null) {
+ if (prop.isMandatory() && !prop.isProtected() && JcrNodeType.RESIDUAL_ITEM_NAME.equals(prop.getName())) {
throw new RepositoryException(JcrI18n.residualDefinitionsCannotBeMandatory.text("properties"));
}
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-04-14 20:06:32 UTC (rev 823)
@@ -0,0 +1,1317 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.jcr;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.PropertyDefinition;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+
+public class TypeRegistrationTest {
+
+ private static final String TEST_TYPE_NAME = "dna:testNode";
+ private static final String TEST_TYPE_NAME2 = "dna:testNode2";
+ private static final String TEST_PROPERTY_NAME = "dna:testProperty";
+ private static final String TEST_CHILD_NODE_NAME = "dna:testChildNode";
+
+ private ExecutionContext context;
+ private RepositoryNodeTypeManager repoTypeManager;
+ private JcrNodeType ntTemplate;
+ private NameFactory nameFactory;
+ private JcrNodeType base;
+ private JcrNodeType referenceable;
+ private JcrNodeType unstructured;
+ private JcrNodeType root;
+ private JcrNodeType versionHistory;
+ private JcrNodeType hierarchyNode;
+ private JcrNodeType file;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ context = new ExecutionContext();
+ nameFactory = context.getValueFactories().getNameFactory();
+
+ JcrNodeTypeSource source = null;
+ source = new JcrBuiltinNodeTypeSource(context, source);
+ source = new DnaBuiltinNodeTypeSource(this.context, source);
+ repoTypeManager = new RepositoryNodeTypeManager(context, source);
+
+ base = repoTypeManager.getNodeType(JcrNtLexicon.BASE);
+ referenceable = repoTypeManager.getNodeType(JcrMixLexicon.REFERENCEABLE);
+ unstructured = repoTypeManager.getNodeType(JcrNtLexicon.UNSTRUCTURED);
+ root = repoTypeManager.getNodeType(DnaLexicon.ROOT);
+ versionHistory = repoTypeManager.getNodeType(JcrNtLexicon.VERSION_HISTORY);
+ hierarchyNode = repoTypeManager.getNodeType(JcrNtLexicon.HIERARCHY_NODE);
+ file = repoTypeManager.getNodeType(JcrNtLexicon.FILE);
+ }
+
+ private Name nameFor( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ private JcrNodeTypeSource sourceFor( final JcrNodeType nodeType ) {
+ return new AbstractJcrNodeTypeSource() {
+ @Override
+ public List<JcrNodeType> getDeclaredNodeTypes() {
+ return Collections.singletonList(nodeType);
+ }
+ };
+ }
+
+ private JcrNodeTypeSource sourceFor( final JcrNodeType... nodeTypes ) {
+ return new AbstractJcrNodeTypeSource() {
+ @Override
+ public List<JcrNodeType> getDeclaredNodeTypes() {
+ return Arrays.asList(nodeTypes);
+ }
+ };
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNullDefinition() throws Exception {
+ repoTypeManager.registerNodeTypes(null);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowTemplateWithNullContext() throws Exception {
+ repoTypeManager.registerNodeTypes(sourceFor(new JcrNodeType(null, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME), Arrays.asList(new JcrNodeType[] {}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES,
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowNodeTypeWithNoName() throws Exception {
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, null,
+ Arrays.asList(new JcrNodeType[] {}), AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES, AbstractJcrNodeTypeSource.NO_PROPERTIES,
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+ repoTypeManager.registerNodeTypes(sourceFor(ntTemplate));
+ }
+
+ @Test
+ public void shouldAllowNewDefinitionWithNoChildNodesOrProperties() throws Exception {
+ Name testTypeName = nameFactory.create(TEST_TYPE_NAME);
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, testTypeName,
+ Arrays.asList(new JcrNodeType[] {}), AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES, AbstractJcrNodeTypeSource.NO_PROPERTIES,
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> testNodeTypes = repoTypeManager.registerNodeTypes(sourceFor(ntTemplate));
+ JcrNodeType testNodeType = testNodeTypes.get(0);
+
+ assertThat(testNodeType.getName(), is(TEST_TYPE_NAME));
+ JcrNodeType nodeTypeFromRepo = repoTypeManager.getNodeType(testTypeName);
+ assertThat(nodeTypeFromRepo, is(notNullValue()));
+ assertThat(nodeTypeFromRepo.getName(), is(TEST_TYPE_NAME));
+ }
+
+ // @Test( expected = RepositoryException.class )
+ // public void shouldNotAllowModificationIfAllowUpdatesIsFalse() throws Exception {
+ // ntTemplate.setName("nt:base");
+ // repoTypeManager.registerNodeType(ntTemplate, false);
+ // }
+
+ // @Test( expected = RepositoryException.class )
+ // public void shouldNotAllowRedefinitionOfNewTypeIfAllowUpdatesIsFalse() throws Exception {
+ // Name testTypeName = nameFactory.create(TEST_TYPE_NAME);
+ // ntTemplate.setName(TEST_TYPE_NAME);
+ // ntTemplate.setDeclaredSupertypeNames(new String[] {"nt:base"});
+ //
+ // JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate, false);
+ //
+ // 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);
+ // }
+
+ @Test
+ public void shouldAllowDefinitionWithExistingSupertypes() throws Exception {
+ Name testTypeName = nameFactory.create(TEST_TYPE_NAME);
+
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, testTypeName,
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME, AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> testNodeTypes = repoTypeManager.registerNodeTypes(sourceFor(ntTemplate));
+ JcrNodeType testNodeType = testNodeTypes.get(0);
+
+ assertThat(testNodeType.getName(), is(TEST_TYPE_NAME));
+ JcrNodeType nodeTypeFromRepo = repoTypeManager.getNodeType(testTypeName);
+ assertThat(nodeTypeFromRepo, is(notNullValue()));
+ assertThat(nodeTypeFromRepo.getName(), is(TEST_TYPE_NAME));
+
+ }
+
+ @Test
+ public void shouldAllowDefinitionWithSupertypesFromTypesRegisteredInSameCall() throws Exception {
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME, AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType ntTemplate2 = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME2), Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, ntTemplate2});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate, ntTemplate2)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowDefinitionWithSupertypesFromTypesRegisteredInSameCallInWrongOrder() throws Exception {
+ // Try to register the supertype AFTER the class that registers it
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME, AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType ntTemplate2 = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME2), Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate2, ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate2, ntTemplate)));
+ }
+
+ @Test
+ public void shouldAllowDefinitionWithAProperty() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.LONG,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false)}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+ }
+
+ @Test
+ public void shouldAllowDefinitionWithProperties() throws Exception {
+
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME, AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {
+ new JcrPropertyDefinition(context, null, null,
+ OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
+ false, AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.LONG, AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),
+ new JcrPropertyDefinition(context, null, null,
+ OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
+ false, AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.STRING, AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ true),
+ new JcrPropertyDefinition(context, null, nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
+ false, AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.STRING, AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false)}), AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowAutocreatedPropertyWithNoDefault() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ true,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.LONG,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowAutocreatedResidualProperty() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ true,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.UNDEFINED,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ // @Test
+ // public void shouldAllowAutocreatedNamedPropertyWithDefault() throws Exception {
+ // ntTemplate.setName(TEST_TYPE_NAME);
+ // ntTemplate.setDeclaredSupertypeNames(new String[] {"nt:base", "mix:referenceable"});
+ //
+ // JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
+ // prop.setName(TEST_PROPERTY_NAME);
+ // prop.setRequiredType(PropertyType.UNDEFINED);
+ // prop.setAutoCreated(true);
+ // prop.setDefaultValues(new String[] {"<default>"});
+ // ntTemplate.getPropertyDefinitionTemplates().add(prop);
+ //
+ // List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
+ // compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false));
+ // }
+ //
+ // @Test( expected = RepositoryException.class )
+ // public void shouldNotAllowSingleValuedPropertyWithMultipleDefaults() throws Exception {
+ // ntTemplate.setName(TEST_TYPE_NAME);
+ // ntTemplate.setDeclaredSupertypeNames(new String[] {"nt:base", "mix:referenceable"});
+ //
+ // JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
+ // prop.setName(TEST_PROPERTY_NAME);
+ // prop.setRequiredType(PropertyType.UNDEFINED);
+ // prop.setAutoCreated(true);
+ // prop.setDefaultValues(new String[] {"<default>", "too many values"});
+ // ntTemplate.getPropertyDefinitionTemplates().add(prop);
+ //
+ // List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
+ // compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false));
+ // }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowMandatoryResidualProperty() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ true,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.UNDEFINED,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ @Test
+ public void shouldAllowTypeWithChildNode() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false, false, false, true,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base})}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ @Test
+ public void shouldAllowTypeWithMultipleChildNodes() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {
+ new JcrNodeDefinition(context, null, nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
+ false, true, JcrNtLexicon.BASE, new JcrNodeType[] {base}),
+ new JcrNodeDefinition(context, null, nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
+ false, false, JcrNtLexicon.BASE, new JcrNodeType[] {unstructured}),
+ new JcrNodeDefinition(context, null, nameFor(TEST_CHILD_NODE_NAME + "2"),
+ OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
+ false, true, JcrNtLexicon.BASE, new JcrNodeType[] {base}),
+
+ }), AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowAutocreatedChildNodeWithNoDefaultPrimaryType() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ true, false, false, false,
+ null, new JcrNodeType[] {base}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowMandatoryResidualChildNode() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false, true, false, false,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingProtectedProperty() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ JcrLexicon.PRIMARY_TYPE,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.NAME,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingProtectedChildNode() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {root, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ JcrLexicon.SYSTEM,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false, false, false, false,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingMandatoryChildNodeWithOptionalChildNode() throws Exception {
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {versionHistory}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ JcrLexicon.ROOT_VERSION,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false, false, false, false,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate)));
+
+ }
+
+ @Test
+ public void shouldAllowOverridingPropertyFromCommonAncestor() throws Exception {
+ /*
+ * testNode declares prop testProperty
+ * testNodeB extends testNode
+ * testNodeC extends testNode
+ * testNodeD extends testNodeB and testNodeC and overrides testProperty --> LEGAL
+ */
+
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.UNDEFINED,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"), Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeCTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "C"), Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeDTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "D"),
+ Arrays.asList(new JcrNodeType[] {nodeBTemplate, nodeCTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.STRING,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate,
+ nodeBTemplate,
+ nodeCTemplate,
+ nodeDTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingPropertyFromDifferentAncestors() throws Exception {
+ /*
+ * testNode
+ * testNodeB extends testNode and declares prop testProperty
+ * testNodeC extends testNode and declares prop testProperty
+ * testNodeD extends testNodeB and testNodeC and overrides testProperty --> ILLEGAL
+ */
+
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME, AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.UNDEFINED,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeCTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "C"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.UNDEFINED,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeDTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "D"),
+ Arrays.asList(new JcrNodeType[] {nodeBTemplate, nodeCTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.STRING,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate,
+ nodeBTemplate,
+ nodeCTemplate,
+ nodeDTemplate)));
+ }
+
+ @Test
+ public void shouldAllowOverridingChildNodeFromCommonAncestor() throws Exception {
+ /*
+ * testNode declares node testChildNode
+ * testNodeB extends testNode
+ * testNodeC extends testNode
+ * testNodeD extends testNodeB and testNodeC and overrides testChildNode --> LEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false, false, false, false,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"), Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeCTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "C"), Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeDTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "D"),
+ Arrays.asList(new JcrNodeType[] {nodeBTemplate, nodeCTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ JcrLexicon.SYSTEM,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ false,
+ JcrNtLexicon.UNSTRUCTURED,
+ new JcrNodeType[] {unstructured}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate,
+ nodeBTemplate,
+ nodeCTemplate,
+ nodeDTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingChildNodeFromDifferentAncestors() throws Exception {
+ /*
+ * testNode
+ * testNodeB extends testNode and declares node testChildNode
+ * testNodeC extends testNode and declares node testChildNode
+ * testNodeD extends testNodeB and testNodeC and overrides testChildNode --> ILLEGAL
+ */
+ ntTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER, nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME, AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ false,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base}),}),
+
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeCTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "C"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ null,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ false,
+ JcrNtLexicon.BASE,
+ new JcrNodeType[] {base}),}),
+
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeDTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "D"),
+ Arrays.asList(new JcrNodeType[] {nodeBTemplate, nodeCTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ JcrLexicon.SYSTEM,
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ false,
+ JcrNtLexicon.UNSTRUCTURED,
+ new JcrNodeType[] {unstructured}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate,
+ nodeBTemplate,
+ nodeCTemplate,
+ nodeDTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowExtendingChildNodeIfSnsChanges() throws Exception {
+ /*
+ * testNode declares node testChildNode with no SNS
+ * testNodeB extends testNode with node testChildNode with SNS -> ILLEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false, false, false, false,
+ null, new JcrNodeType[] {root}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ true,
+ JcrNtLexicon.UNSTRUCTURED,
+ new JcrNodeType[] {unstructured}),}),
+
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate,});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate, nodeBTemplate)));
+
+ }
+
+ @Test
+ public void shouldAllowExtendingPropertyIfMultipleChanges() throws Exception {
+ /*
+ * testNode declares SV property testProperty
+ * testNodeB extends testNode with MV property testProperty with incompatible type -> LEGAL
+ * testNodeC extends testNode, testNodeB -> LEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.LONG,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.DATE,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ true),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeCTemplate = new JcrNodeType(context, AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "C"), Arrays.asList(new JcrNodeType[] {ntTemplate,
+ nodeBTemplate}), AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate, nodeCTemplate,});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate,
+ nodeBTemplate,
+ nodeCTemplate)));
+ }
+
+ @Test
+ public void shouldAllowOverridingPropertyIfTypeNarrows() throws Exception {
+ /*
+ * testNode declares SV property testProperty of type UNDEFINED
+ * testNodeB extends testNode with SV property testProperty of type STRING -> LEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.STRING,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.LONG,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate,});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate, nodeBTemplate)));
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingPropertyIfTypeDoesNotNarrow() throws Exception {
+ /*
+ * testNode declares SV property testProperty of type DATE
+ * testNodeB extends testNode with SV property testProperty of type NAME -> ILLEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.DATE,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN, AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ AbstractJcrNodeTypeSource.NO_CHILD_NODES,
+ Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition(
+ context,
+ null,
+ nameFor(TEST_PROPERTY_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ AbstractJcrNodeTypeSource.NO_DEFAULT_VALUES,
+ PropertyType.NAME,
+ AbstractJcrNodeTypeSource.NO_CONSTRAINTS,
+ false),}),
+ AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate,});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate, nodeBTemplate)));
+ }
+
+ @Test
+ public void shouldAllowOverridingChildNodeIfRequiredTypesNarrow() throws Exception {
+ /*
+ * testNode declares No-SNS childNode testChildNode requiring type nt:hierarchy
+ * testNodeB extends testNode with No-SNS childNode testChildNode requiring type nt:file -> LEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ false,
+ null,
+ new JcrNodeType[] {hierarchyNode}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ true,
+ null,
+ new JcrNodeType[] {file}),}),
+
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate,});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate, nodeBTemplate)));
+
+ }
+
+ @Test( expected = RepositoryException.class )
+ public void shouldNotAllowOverridingChildNodeIfRequiredTypesDoNotNarrow() throws Exception {
+ /*
+ * testNode declares No-SNS childNode testChildNode requiring type nt:hierarchy
+ * testNodeB extends testNode with No-SNS childNode testChildNode requiring type nt:base -> ILLEGAL
+ */
+ ntTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME),
+ Arrays.asList(new JcrNodeType[] {base, referenceable}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ false,
+ null,
+ new JcrNodeType[] {hierarchyNode}),}),
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ JcrNodeType nodeBTemplate = new JcrNodeType(
+ context,
+ AbstractJcrNodeTypeSource.NO_NODE_TYPE_MANAGER,
+ nameFor(TEST_TYPE_NAME + "B"),
+ Arrays.asList(new JcrNodeType[] {ntTemplate}),
+ AbstractJcrNodeTypeSource.NO_PRIMARY_ITEM_NAME,
+ Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition(
+ context,
+ null,
+ nameFor(TEST_CHILD_NODE_NAME),
+ OnParentVersionBehavior.VERSION.getJcrValue(),
+ false,
+ false,
+ false,
+ true,
+ null,
+ new JcrNodeType[] {base}),}),
+
+ AbstractJcrNodeTypeSource.NO_PROPERTIES, AbstractJcrNodeTypeSource.NOT_MIXIN,
+ AbstractJcrNodeTypeSource.UNORDERABLE_CHILD_NODES);
+
+ List<JcrNodeType> templates = Arrays.asList(new JcrNodeType[] {ntTemplate, nodeBTemplate,});
+ compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(sourceFor(ntTemplate, nodeBTemplate)));
+
+ }
+
+ private void compareTemplatesToNodeTypes( List<JcrNodeType> templates,
+ List<JcrNodeType> nodeTypes ) {
+ assertThat(templates.size(), is(nodeTypes.size()));
+
+ for (int i = 0; i < nodeTypes.size(); i++) {
+ JcrNodeType jntt = templates.get(i);
+ compareTemplateToNodeType(jntt, null);
+ compareTemplateToNodeType(jntt, nodeTypes.get(i));
+ }
+ }
+
+ private void compareTemplateToNodeType( JcrNodeType template,
+ JcrNodeType nodeType ) {
+ Name nodeTypeName = nameFactory.create(template.getName());
+ if (nodeType == null) {
+ nodeType = repoTypeManager.getNodeType(nodeTypeName);
+ assertThat(nodeType.nodeTypeManager(), is(notNullValue()));
+ }
+
+ assertThat(nodeType, is(notNullValue()));
+ assertThat(nodeType.getName(), is(template.getName()));
+
+ assertThat(nodeType.getDeclaredSupertypes().length, is(template.getDeclaredSupertypes().length));
+ for (int i = 0; i < template.getDeclaredSupertypes().length; i++) {
+ assertThat(template.getDeclaredSupertypes()[i].getName(), is(nodeType.getDeclaredSupertypes()[i].getName()));
+ }
+ assertThat(template.isMixin(), is(nodeType.isMixin()));
+ assertThat(template.hasOrderableChildNodes(), is(nodeType.hasOrderableChildNodes()));
+
+ PropertyDefinition[] propertyDefs = nodeType.getDeclaredPropertyDefinitions();
+ List<JcrPropertyDefinition> propertyTemplates = Arrays.asList(template.getDeclaredPropertyDefinitions());
+
+ assertThat(propertyDefs.length, is(propertyTemplates.size()));
+ for (JcrPropertyDefinition pt : propertyTemplates) {
+ JcrPropertyDefinition propertyTemplate = pt;
+
+ PropertyDefinition matchingDefinition = null;
+ for (int i = 0; i < propertyDefs.length; i++) {
+ PropertyDefinition pd = propertyDefs[i];
+
+ String ptName = propertyTemplate.getName() == null ? JcrNodeType.RESIDUAL_ITEM_NAME : propertyTemplate.getName();
+ if (pd.getName().equals(ptName) && pd.getRequiredType() == propertyTemplate.getRequiredType()
+ && pd.isMultiple() == propertyTemplate.isMultiple()) {
+ matchingDefinition = pd;
+ break;
+ }
+ }
+
+ comparePropertyTemplateToPropertyDefinition(propertyTemplate, (JcrPropertyDefinition)matchingDefinition);
+ }
+
+ NodeDefinition[] childNodeDefs = nodeType.getDeclaredChildNodeDefinitions();
+ List<JcrNodeDefinition> childNodeTemplates = Arrays.asList(template.getDeclaredChildNodeDefinitions());
+
+ assertThat(childNodeDefs.length, is(childNodeTemplates.size()));
+ for (JcrNodeDefinition nt : childNodeTemplates) {
+ JcrNodeDefinition childNodeTemplate = nt;
+
+ NodeDefinition matchingDefinition = null;
+ for (int i = 0; i < childNodeDefs.length; i++) {
+ JcrNodeDefinition nd = (JcrNodeDefinition)childNodeDefs[i];
+
+ String ntName = childNodeTemplate.getName() == null ? JcrNodeType.RESIDUAL_ITEM_NAME : childNodeTemplate.getName();
+ if (nd.getName().equals(ntName) && nd.allowsSameNameSiblings() == childNodeTemplate.allowsSameNameSiblings()) {
+
+ boolean matchesOnRequiredTypes = childNodeTemplate.getRequiredPrimaryTypeNames()
+ .equals(nd.getRequiredPrimaryTypeNames());
+
+ if (matchesOnRequiredTypes) {
+ matchingDefinition = nd;
+ break;
+ }
+ }
+ }
+
+ compareNodeTemplateToNodeDefinition(childNodeTemplate, (JcrNodeDefinition)matchingDefinition);
+ }
+
+ }
+
+ private void comparePropertyTemplateToPropertyDefinition( JcrPropertyDefinition template,
+ JcrPropertyDefinition definition ) {
+
+ assertThat(definition, is(notNullValue()));
+ assertThat(definition.getDeclaringNodeType(), is(notNullValue()));
+ // Had to match on name to even get to the definition
+ // assertThat(template.getName(), is(definition.getName()));
+
+ assertThat(template.getValueConstraints(), is(definition.getValueConstraints()));
+ assertThat(template.getOnParentVersion(), is(definition.getOnParentVersion()));
+ assertThat(template.getRequiredType(), is(definition.getRequiredType()));
+ assertThat(template.isAutoCreated(), is(definition.isAutoCreated()));
+ assertThat(template.isMandatory(), is(definition.isMandatory()));
+ assertThat(template.isMultiple(), is(definition.isMultiple()));
+ assertThat(template.isProtected(), is(definition.isProtected()));
+ }
+
+ private void compareNodeTemplateToNodeDefinition( JcrNodeDefinition template,
+ JcrNodeDefinition definition ) {
+ assertThat(definition, is(notNullValue()));
+ assertThat(definition.getDeclaringNodeType(), is(notNullValue()));
+ // Had to match on name to even get to the definition
+ // assertThat(template.getName(), is(definition.getName()));
+
+ assertThat(template.getOnParentVersion(), is(definition.getOnParentVersion()));
+ assertThat(template.isAutoCreated(), is(definition.isAutoCreated()));
+ assertThat(template.isMandatory(), is(definition.isMandatory()));
+ assertThat(template.isProtected(), is(definition.isProtected()));
+
+ assertThat(template.with(repoTypeManager).getDefaultPrimaryType(), is(definition.getDefaultPrimaryType()));
+ assertThat(template.allowsSameNameSiblings(), is(definition.allowsSameNameSiblings()));
+
+ // assertThat(template.getRequiredPrimaryTypeNames(), is(definition.getRequiredPrimaryTypeNames()));
+
+ }
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
17 years
DNA SVN: r822 - trunk/dna-jcr/src/test/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-14 12:41:54 -0400 (Tue, 14 Apr 2009)
New Revision: 822
Added:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrAccessTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrReadingTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWritingTest.java
Log:
DNA-351 Performance Test for JCR Access
Applied the patch, which adds a number of new simple performance tests for measuring reads and writes through the JCR layer.
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrAccessTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrAccessTest.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrAccessTest.java 2009-04-14 16:41:54 UTC (rev 822)
@@ -0,0 +1,271 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.jcr;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.io.PrintStream;
+import java.util.concurrent.TimeUnit;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import org.jboss.dna.common.statistic.Stopwatch;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.property.PathFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Support class for performance testing of various operations over subtrees of the content graph
+ */
+
+public abstract class AbstractJcrAccessTest {
+
+ private InMemoryRepositorySource source;
+ private JcrSession session;
+ private JcrRepository repository;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ String workspaceName = "workspace1";
+
+ // Set up the source ...
+ source = new InMemoryRepositorySource();
+ source.setName(workspaceName);
+ source.setDefaultWorkspaceName(workspaceName);
+
+ // Set up the execution context ...
+ ExecutionContext context = new ExecutionContext();
+ // Register the test namespace
+ context.getNamespaceRegistry().register(TestLexicon.Namespace.PREFIX, TestLexicon.Namespace.URI);
+
+ // Set up the initial content ...
+ Graph graph = Graph.create(source, context);
+
+ // Make sure the path to the namespaces exists ...
+ graph.create("/jcr:system"); // .and().create("/jcr:system/dna:namespaces");
+ graph.set("jcr:primaryType").on("/jcr:system").to(DnaLexicon.SYSTEM);
+
+ // Stub out the connection factory ...
+ RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositoryConnectionFactory#createConnection(java.lang.String)
+ */
+ @SuppressWarnings( "synthetic-access" )
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ return source.getConnection();
+ }
+ };
+
+ repository = new JcrRepository(context, connectionFactory, "unused");
+
+ session = (JcrSession) repository.login();
+ }
+
+ @After
+ public void after() throws Exception {
+ if (session != null && session.isLive()) {
+ session.logout();
+ }
+ }
+
+ protected JcrSession session() {
+ return this.session;
+ }
+
+ private String getRandomString(int length) {
+ StringBuffer buff = new StringBuffer(length);
+
+ for (int i = 0; i < length; i++) {
+ buff.append((char) ((Math.random() *26) + 'a'));
+ }
+
+ return buff.toString();
+ }
+
+ private int createChildren(Node parent, int numProperties, int width, int depth)
+ throws Exception
+ {
+ if (depth < 1) {
+ return 0;
+
+ }
+
+ int count = width;
+
+ for (int i = 0; i < width; i++) {
+ Node newNode = parent.addNode(getRandomString(9), "nt:unstructured");
+
+ for (int j = 0; j < numProperties; j++) {
+ newNode.setProperty(getRandomString(8), getRandomString(16));
+ }
+
+ count += createChildren(newNode, numProperties, width, depth - 1);
+ }
+ return count;
+ }
+
+ protected int createSubgraph( JcrSession session,
+ String initialPath,
+ int depth,
+ int numberOfChildrenPerNode,
+ int numberOfPropertiesPerNode,
+ boolean oneBatch,
+ Stopwatch stopwatch,
+ PrintStream output,
+ String description )
+ throws Exception
+ {
+ // Calculate the number of nodes that we'll created, but subtract 1 since it doesn't create the root
+ long totalNumber = calculateTotalNumberOfNodesInTree(numberOfChildrenPerNode, depth, false);
+ if (initialPath == null) initialPath = "";
+ if (description == null) {
+ description = "" + numberOfChildrenPerNode + "x" + depth + " tree with " + numberOfPropertiesPerNode
+ + " properties per node";
+ }
+
+ if (output != null) output.println(description + " (" + totalNumber + " nodes):");
+ long totalNumberCreated = 0;
+
+ PathFactory pathFactory = session.getExecutionContext().getValueFactories().getPathFactory();
+ Node parentNode = session.getNode(pathFactory.create(initialPath));
+
+ if (stopwatch != null) stopwatch.start();
+
+ totalNumberCreated += createChildren(parentNode,
+ numberOfPropertiesPerNode,
+ numberOfChildrenPerNode,
+ depth);
+
+ assertThat(totalNumberCreated, is(totalNumber));
+
+ session.save();
+
+
+ if (stopwatch != null) {
+ stopwatch.stop();
+ if (output != null) {
+ output.println(" " + getTotalAndAverageDuration(stopwatch, totalNumberCreated));
+ }
+ }
+ return (int)totalNumberCreated;
+
+ }
+
+ protected int traverseSubgraph( JcrSession session,
+ String initialPath,
+ int depth,
+ int numberOfChildrenPerNode,
+ int numberOfPropertiesPerNode,
+ boolean oneBatch,
+ Stopwatch stopwatch,
+ PrintStream output,
+ String description )
+ throws Exception
+ {
+ // Calculate the number of nodes that we'll created, but subtract 1 since it doesn't create the root
+ long totalNumber = calculateTotalNumberOfNodesInTree(numberOfChildrenPerNode, depth, false);
+ if (initialPath == null) initialPath = "";
+ if (description == null) {
+ description = "" + numberOfChildrenPerNode + "x" + depth + " tree with " + numberOfPropertiesPerNode
+ + " properties per node";
+ }
+
+ if (output != null) output.println(description + " (" + totalNumber + " nodes):");
+ long totalNumberTraversed = 0;
+
+ PathFactory pathFactory = session.getExecutionContext().getValueFactories().getPathFactory();
+ Node parentNode = session.getNode(pathFactory.create(initialPath));
+
+ if (stopwatch != null) stopwatch.start();
+
+ totalNumberTraversed += traverseChildren(parentNode);
+
+ assertThat(totalNumberTraversed, is(totalNumber));
+
+ session.save();
+
+
+ if (stopwatch != null) {
+ stopwatch.stop();
+ if (output != null) {
+ output.println(" " + getTotalAndAverageDuration(stopwatch, totalNumberTraversed));
+ }
+ }
+ return (int)totalNumberTraversed;
+
+ }
+
+ protected int traverseChildren(Node parentNode) throws Exception {
+
+ int childCount = 0;
+ NodeIterator children = parentNode.getNodes();
+
+ while (children.hasNext()) {
+ childCount++;
+
+ childCount += traverseChildren(children.nextNode());
+ }
+
+ return childCount;
+ }
+
+ protected String getTotalAndAverageDuration( Stopwatch stopwatch,
+ long numNodes ) {
+ long totalDurationInMilliseconds = TimeUnit.NANOSECONDS.toMillis(stopwatch.getTotalDuration().longValue());
+ if (numNodes == 0) numNodes = 1;
+ long avgDuration = totalDurationInMilliseconds / numNodes;
+ String units = " millisecond(s)";
+ if (avgDuration < 1L) {
+ long totalDurationInMicroseconds = TimeUnit.NANOSECONDS.toMicros(stopwatch.getTotalDuration().longValue());
+ avgDuration = totalDurationInMicroseconds / numNodes;
+ units = " microsecond(s)";
+ }
+ return "total = " + stopwatch.getTotalDuration() + "; avg = " + avgDuration + units;
+ }
+
+ protected int calculateTotalNumberOfNodesInTree( int numberOfChildrenPerNode,
+ int depth,
+ boolean countRoot ) {
+ assert depth > 0;
+ assert numberOfChildrenPerNode > 0;
+ int totalNumber = 0;
+ for (int i = 0; i <= depth; ++i) {
+ totalNumber += (int)Math.pow(numberOfChildrenPerNode, i);
+ }
+ return countRoot ? totalNumber : totalNumber - 1;
+ }
+
+
+
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrAccessTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrReadingTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrReadingTest.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrReadingTest.java 2009-04-14 16:41:54 UTC (rev 822)
@@ -0,0 +1,52 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.jcr;
+
+import org.jboss.dna.common.statistic.Stopwatch;
+import org.junit.Test;
+
+/**
+ * Test performance reading graph subtrees of various sizes with varying number of properties
+ */
+public class JcrReadingTest extends AbstractJcrAccessTest {
+
+ @Test
+ public void testReadingTrees() throws Exception {
+ int[] breadths = new int[] { 10, };
+ int[] depths = new int[] { 1, 2, 3, };
+ int[] properties = new int[] { 0, 7, 100 };
+
+ for (int i = 0; i < breadths.length; i++) {
+ for (int j = 0; j < depths.length; j++) {
+ for (int k = 0; k < properties.length; k++) {
+ String testName = "/" + breadths[i] + "x" + depths[j] + "x" + properties[k] + "test";
+ session().getRootNode().addNode(testName, "nt:unstructured");
+ createSubgraph(session(), testName, depths[j], breadths[i], properties[k], false, null, null, null);
+
+ traverseSubgraph(session(), testName, depths[j], breadths[i], properties[k], false, new Stopwatch(), System.out, null);
+ }
+ }
+ }
+ }
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrReadingTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWritingTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWritingTest.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWritingTest.java 2009-04-14 16:41:54 UTC (rev 822)
@@ -0,0 +1,51 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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.jboss.dna.jcr;
+
+import org.jboss.dna.common.statistic.Stopwatch;
+import org.junit.Test;
+
+
+/**
+ * Test performance writing graph subtrees of various sizes with varying number of properties
+ */
+public class JcrWritingTest extends AbstractJcrAccessTest {
+
+ @Test
+ public void testCreatingTrees() throws Exception {
+ int[] breadths = new int[] { 10, };
+ int[] depths = new int[] { 1, 2, 3, };
+ int[] properties = new int[] { 0, 7, 100 };
+
+ for (int i = 0; i < breadths.length; i++) {
+ for (int j = 0; j < depths.length; j++) {
+ for (int k = 0; k < properties.length; k++) {
+ String testName = "/" + breadths[i] + "x" + depths[j] + "x" + properties[k] + "test";
+ session().getRootNode().addNode(testName, "nt:unstructured");
+ createSubgraph(session(), testName, depths[j], breadths[i], properties[k], false, new Stopwatch(), System.out, null);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWritingTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
17 years
DNA SVN: r821 - trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-14 12:29:42 -0400 (Tue, 14 Apr 2009)
New Revision: 821
Modified:
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
Log:
Minor correction to one localized message.
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-04-14 16:13:03 UTC (rev 820)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-04-14 16:29:42 UTC (rev 821)
@@ -80,7 +80,7 @@
nodeHasAlreadyBeenRemovedFromThisSession = Node "{0}" in workspace "{1} has already been removed from this session
REP_NAME_DESC = DNA Repository
-REP_VENDOR_DESC = JBoss - A division of Red Hat Middleware LLC
+REP_VENDOR_DESC = JBoss - A division of Red Hat
SPEC_NAME_DESC = Content Repository for Java Technology API
errorObtainingWorkspaceNames = Error while obtaining the workspace names for the "{0}" repository: {1}
17 years
DNA SVN: r820 - in trunk/dna-jcr/src/main: resources/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-14 12:13:03 -0400 (Tue, 14 Apr 2009)
New Revision: 820
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
Log:
DNA-339 JCR Type Registration and Unregistration
Applying the patch, with some very minor modifications (particularly, some additional JavaDoc in NodeDefinitionId and PropertyDefinitionId). The Key classes in JcrPropertyDefinition and JcrNodeDefinition should be replaced with PropertyDefinitionId and NodeDefinitionId, respectively, but this can be done in another change set. The current approach works, but may actually not match the specification. (The JavaDoc added to the *DefinitionId classes helps to explain what information exactly is used to distinguish the definitions, and the Key classes use a different set of information.)
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -76,6 +76,7 @@
public static I18n errorWhileFindingNodeWithUuid;
public static I18n errorWhileFindingNodeWithPath;
public static I18n nodeDefinitionCouldNotBeDeterminedForNode;
+ public static I18n noSnsDefinitionForNode;
public static I18n missingNodeTypeForExistingNode;
public static I18n unableToCreateNodeWithPrimaryTypeThatDoesNotExist;
public static I18n unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition;
@@ -109,6 +110,23 @@
public static I18n notStoredQuery;
public static I18n invalidQueryLanguage;
+ // Type registration messages
+ public static I18n invalidNodeTypeName;
+ public static I18n nodeTypeAlreadyExists;
+ public static I18n invalidPrimaryTypeName;
+ public static I18n invalidSupertypeName;
+ public static I18n supertypesConflict;
+ public static I18n ambiguousPrimaryItemName;
+ public static I18n invalidPrimaryItemName;
+ public static I18n autocreatedNodesNeedDefaults;
+ public static I18n residualDefinitionsCannotBeMandatory;
+ public static I18n cannotOverrideProtectedDefinition;
+ public static I18n cannotMakeMandatoryDefinitionOptional;
+ public static I18n constraintsChangedInSubtype;
+ public static I18n cannotRedefineProperty;
+ public static I18n autocreatedPropertyNeedsDefault;
+ public static I18n singleValuedPropertyNeedsSingleValuedDefault;
+
static {
try {
I18n.initialize(JcrI18n.class);
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -27,11 +27,15 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Value;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
/**
* DNA implementation of the {@link NodeDefinition} class.
@@ -218,4 +222,73 @@
return getId().toString();
}
+ Key getKey(boolean includeTypes) {
+ return new Key(this, includeTypes);
+ }
+
+ /**
+ * Internal class that encapsulates composite unique identifier for child node definitions
+ */
+ class Key {
+ String keyString;
+
+ Key( Node node,
+ NamespaceRegistry registry ) throws Exception {
+ StringBuffer buff = new StringBuffer();
+
+ try {
+ String nodeName = node.getProperty(JcrLexicon.NAME.getString(registry)).getString();
+ buff.append(nodeName);
+ } catch (PathNotFoundException pnfe) {
+ // Ignorable, means name is not set.
+ buff.append(JcrNodeType.RESIDUAL_ITEM_NAME);
+ }
+
+ try {
+ Value[] requiredTypes = node.getProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES.getString(registry)).getValues();
+
+ for (int i = 0; i < requiredTypes.length; i++) {
+ buff.append('_').append(requiredTypes[i].getString());
+ }
+ } catch (PathNotFoundException pnfe) {
+ // No required types. Weird, but not debilitating.
+ }
+
+ buff.append('_').append(node.getProperty(JcrLexicon.SAME_NAME_SIBLINGS.getString(registry)).getBoolean());
+
+ this.keyString = buff.toString();
+ }
+
+ Key( NodeDefinition def,
+ boolean includeTypes ) {
+ StringBuffer buff = new StringBuffer();
+ buff.append(def.getName());
+
+ if (includeTypes) {
+ NodeType[] requiredTypes = def.getRequiredPrimaryTypes();
+ for (int i = 0; i < requiredTypes.length; i++) {
+ buff.append('_').append(requiredTypes[i].getName());
+ }
+ }
+
+ buff.append('_').append(def.allowsSameNameSiblings());
+
+ this.keyString = buff.toString();
+ }
+
+ @Override
+ public boolean equals( Object ob ) {
+ if (!(ob instanceof Key)) {
+ return false;
+ }
+
+ return keyString.equals(((Key)ob).keyString);
+ }
+
+ @Override
+ public int hashCode() {
+ return keyString.hashCode();
+ }
+ }
+
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -34,7 +34,6 @@
import java.util.Set;
import javax.jcr.PropertyType;
import javax.jcr.Value;
-import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
import net.jcip.annotations.Immutable;
@@ -334,7 +333,7 @@
*
* @see javax.jcr.nodetype.NodeType#getDeclaredChildNodeDefinitions()
*/
- public NodeDefinition[] getDeclaredChildNodeDefinitions() {
+ public JcrNodeDefinition[] getDeclaredChildNodeDefinitions() {
// Always have to make a copy to prevent changes ...
return childNodeDefinitions.toArray(new JcrNodeDefinition[childNodeDefinitions.size()]);
}
@@ -344,10 +343,10 @@
*
* @see javax.jcr.nodetype.NodeType#getChildNodeDefinitions()
*/
- public NodeDefinition[] getChildNodeDefinitions() {
+ public JcrNodeDefinition[] getChildNodeDefinitions() {
// Always have to make a copy to prevent changes ...
Collection<JcrNodeDefinition> definitions = this.allDefinitions.allChildNodeDefinitions();
- return definitions.toArray(new NodeDefinition[definitions.size()]);
+ return definitions.toArray(new JcrNodeDefinition[definitions.size()]);
}
/**
@@ -355,10 +354,10 @@
*
* @see javax.jcr.nodetype.NodeType#getPropertyDefinitions()
*/
- public PropertyDefinition[] getPropertyDefinitions() {
+ public JcrPropertyDefinition[] getPropertyDefinitions() {
// Always have to make a copy to prevent changes ...
Collection<JcrPropertyDefinition> definitions = this.allDefinitions.allPropertyDefinitions();
- return definitions.toArray(new PropertyDefinition[definitions.size()]);
+ return definitions.toArray(new JcrPropertyDefinition[definitions.size()]);
}
/**
@@ -366,9 +365,9 @@
*
* @see javax.jcr.nodetype.NodeType#getDeclaredSupertypes()
*/
- public NodeType[] getDeclaredSupertypes() {
+ public JcrNodeType[] getDeclaredSupertypes() {
// Always have to make a copy to prevent changes ...
- return declaredSupertypes.toArray(new NodeType[declaredSupertypes.size()]);
+ return declaredSupertypes.toArray(new JcrNodeType[declaredSupertypes.size()]);
}
/**
@@ -382,16 +381,26 @@
}
/**
- * Returns the internal {@link Name} object for the note type. This method exists outside the JCR API and should not be
+ * Returns the internal {@link Name} object for the node type. This method exists outside the JCR API and should not be
* exposed outside of the package.
*
- * @return the internal {@link Name} object for the note type.
+ * @return the internal {@link Name} object for the node type.
*/
Name getInternalName() {
return name;
}
/**
+ * Returns the internal {@link Name} object for the primary item of this node type. This method exists outside the JCR API and
+ * should not be exposed outside of the package.
+ *
+ * @return the internal {@link Name} object for the primary item of this node type.
+ */
+ Name getInternalPrimaryItemName() {
+ return primaryItemName;
+ }
+
+ /**
* {@inheritDoc}
*
* @see javax.jcr.nodetype.NodeType#getPrimaryItemName()
@@ -410,7 +419,7 @@
*
* @see javax.jcr.nodetype.NodeType#getDeclaredPropertyDefinitions()
*/
- public PropertyDefinition[] getDeclaredPropertyDefinitions() {
+ public JcrPropertyDefinition[] getDeclaredPropertyDefinitions() {
return propertyDefinitions.toArray(new JcrPropertyDefinition[propertyDefinitions.size()]);
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -26,6 +26,7 @@
import java.util.UUID;
import java.util.regex.Pattern;
import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
@@ -36,6 +37,7 @@
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.ValueFactories;
@@ -139,6 +141,20 @@
}
/**
+ * Creates a new <code>JcrPropertyDefinition</code> that is identical to the current object, but with the given
+ * <code>context</code>. Provided to support immutable pattern for this class.
+ *
+ * @param context the {@link ExecutionContext} for the new <code>JcrPropertyDefinition</code>
+ * @return a new <code>JcrPropertyDefinition</code> that is identical to the current object, but with the given
+ * <code>context</code>.
+ */
+ JcrPropertyDefinition with( ExecutionContext context) {
+ return new JcrPropertyDefinition(context, this.declaringNodeType, this.name, this.getOnParentVersion(),
+ this.isAutoCreated(), this.isMandatory(), this.isProtected(), this.getDefaultValues(),
+ this.getRequiredType(), this.getValueConstraints(), this.isMultiple());
+ }
+
+ /**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
@@ -673,4 +689,51 @@
return false;
}
}
+
+ Key getKey(boolean includeType) {
+ return new Key(this, includeType);
+ }
+
+ /**
+ * Internal class that encapsulates composite unique identifier for property definitions
+ */
+ class Key {
+ String keyString;
+
+ Key( Node node,
+ NamespaceRegistry registry ) throws Exception {
+ String propertyName = JcrNodeType.RESIDUAL_ITEM_NAME;
+
+ try {
+ propertyName = node.getProperty(JcrLexicon.NAME.getString(registry)).getString();
+ } catch (PathNotFoundException pnfe) {
+ // Ignorable, means name is not set.
+ }
+ String requiredType = node.getProperty(JcrLexicon.REQUIRED_TYPE.getString(registry)).getString();
+ boolean allowsMultiple = node.getProperty(JcrLexicon.MULTIPLE.getString(registry)).getBoolean();
+
+ this.keyString = propertyName + "-" + requiredType + "-" + allowsMultiple;
+ }
+
+ Key( PropertyDefinition def, boolean includeType ) {
+ String requiredType = PropertyType.nameFromValue(def.getRequiredType());
+
+ this.keyString = def.getName() + (includeType ? "-" + requiredType : "") + "-" + def.isMultiple();
+ }
+
+ @Override
+ public boolean equals( Object ob ) {
+ if (!(ob instanceof Key)) {
+ return false;
+ }
+
+ return keyString.equals(((Key)ob).keyString);
+ }
+
+ @Override
+ public int hashCode() {
+ return keyString.hashCode();
+ }
+ }
+
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -166,6 +166,10 @@
return this.executionContext.getNamespaceRegistry();
}
+ JcrWorkspace workspace() {
+ return this.workspace;
+ }
+
/**
* {@inheritDoc}
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -175,6 +175,10 @@
return this.nodeTypeManager;
}
+ final ExecutionContext context() {
+ return this.context;
+ }
+
/**
* {@inheritDoc}
*/
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -24,6 +24,7 @@
package org.jboss.dna.jcr;
import java.io.Serializable;
+import java.util.HashMap;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
@@ -34,6 +35,19 @@
* within the graph as {@link #getString() string values} on a property. These string values can later be
* {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
* use namespace prefixes, so they are long-lasting and durable.
+ * <p>
+ * What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
+ * version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
+ * The proposed draft of the JSR-283 specification does clarify this more: Section 4.7.15 says :
+ * </p>
+ * <p>
+ * <quote>"Similarly, a node type may have two or more child node definitions with identical name attributes as long as they are
+ * distinguishable by the required primary types attribute (the value returned by
+ * NodeDefinition.getRequiredPrimaryTypes)."</quote>
+ * </p>
+ * <p>
+ * This class is {@link Serializable} and designed to be used as a key in a {@link HashMap}.
+ * </p>
*/
@Immutable
public final class NodeDefinitionId implements Serializable {
@@ -51,7 +65,10 @@
private final Name nodeTypeName;
private final Name childDefinitionName;
private final Name[] requiredPrimaryTypes;
- private final String stringVersion;
+ /**
+ * A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
+ */
+ private final String stringRepresentation;
/**
* Create an identifier for a node definition.
@@ -75,7 +92,7 @@
sb.append('/');
sb.append(requiredPrimaryType.getString());
}
- this.stringVersion = sb.toString();
+ this.stringRepresentation = sb.toString();
}
/**
@@ -121,7 +138,7 @@
* @return the string form
*/
public String getString() {
- return this.stringVersion;
+ return this.stringRepresentation;
}
/**
@@ -153,7 +170,7 @@
*/
@Override
public int hashCode() {
- return stringVersion.hashCode();
+ return stringRepresentation.hashCode();
}
/**
@@ -166,7 +183,7 @@
if (obj == this) return true;
if (obj instanceof NodeDefinitionId) {
NodeDefinitionId that = (NodeDefinitionId)obj;
- return this.stringVersion.equals(that.stringVersion);
+ return this.stringRepresentation.equals(that.stringRepresentation);
}
return false;
}
@@ -178,7 +195,7 @@
*/
@Override
public String toString() {
- return this.stringVersion;
+ return this.stringRepresentation;
}
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -24,6 +24,7 @@
package org.jboss.dna.jcr;
import java.io.Serializable;
+import java.util.HashMap;
import javax.jcr.PropertyType;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.property.Name;
@@ -35,6 +36,20 @@
* stored within the graph as {@link #getString() string values} on a property. These string values can later be
* {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
* use namespace prefixes, so they are long-lasting and durable.
+ * <p>
+ * What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
+ * version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
+ * The proposed draft of the JSR-283 specification does clarify this more: Section 4.7.15 says :
+ * </p>
+ * <p>
+ * <quote>"A node type may have two or more property definitions with identical name attributes (the value returned by
+ * ItemDefinition.getName) as long as the definitions are otherwise distinguishable by either the required type attribute (the
+ * value returned by PropertyDefinition.getRequiredType) or the multiple attribute (the value returned by
+ * PropertyDefinition.isMultiple)."</quote>
+ * </p>
+ * <p>
+ * This class is {@link Serializable} and designed to be used as a key in a {@link HashMap}.
+ * </p>
*/
@Immutable
public final class PropertyDefinitionId implements Serializable {
@@ -53,7 +68,10 @@
private final Name propertyDefinitionName;
private final int propertyType;
private final boolean allowsMultiple;
- private final String stringVersion;
+ /**
+ * A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
+ */
+ private final String stringRepresentation;
/**
* Create a new identifier for a propety definition.
@@ -73,8 +91,8 @@
this.propertyDefinitionName = propertyDefinitionName;
this.propertyType = propertyType;
this.allowsMultiple = allowsMultiple;
- this.stringVersion = this.nodeTypeName.getString() + '/' + this.propertyDefinitionName.getString() + '/'
- + PropertyType.nameFromValue(propertyType) + '/' + (allowsMultiple ? '*' : '1');
+ this.stringRepresentation = this.nodeTypeName.getString() + '/' + this.propertyDefinitionName.getString() + '/'
+ + PropertyType.nameFromValue(propertyType) + '/' + (allowsMultiple ? '*' : '1');
}
/**
@@ -129,7 +147,7 @@
* @return the string form
*/
public String getString() {
- return this.stringVersion;
+ return this.stringRepresentation;
}
/**
@@ -167,7 +185,7 @@
*/
@Override
public int hashCode() {
- return this.stringVersion.hashCode();
+ return this.stringRepresentation.hashCode();
}
/**
@@ -180,7 +198,7 @@
if (obj == this) return true;
if (obj instanceof PropertyDefinitionId) {
PropertyDefinitionId that = (PropertyDefinitionId)obj;
- return this.stringVersion.equals(that.stringVersion);
+ return this.stringRepresentation.equals(that.stringRepresentation);
}
return false;
}
@@ -192,7 +210,7 @@
*/
@Override
public String toString() {
- return this.stringVersion;
+ return this.stringRepresentation;
}
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-04-14 16:13:03 UTC (rev 820)
@@ -24,7 +24,9 @@
package org.jboss.dna.jcr;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -32,6 +34,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
@@ -47,6 +50,7 @@
import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.jcr.JcrNodeTypeSource;
/**
* The {@link RepositoryNodeTypeManager} is the maintainer of node type information for the entire repository at run-time. The
@@ -70,6 +74,27 @@
private final PropertyFactory propertyFactory;
private final PathFactory pathFactory;
+ /**
+ * List of ways to filter the returned property definitions
+ *
+ * @see RepositoryNodeTypeManager#findPropertyDefinitions(List, Name, PropertyCardinality, List)
+ */
+ private enum PropertyCardinality {
+ SINGLE_VALUED_ONLY,
+ MULTI_VALUED_ONLY,
+ ANY
+ }
+
+ /**
+ * List of ways to filter the returned node definitions
+ *
+ * @see RepositoryNodeTypeManager#findChildNodeDefinitions(List, Name, NodeCardinality, List)
+ */
+ private enum NodeCardinality {
+ NO_SAME_NAME_SIBLINGS,
+ SAME_NAME_SIBLINGS
+ }
+
RepositoryNodeTypeManager( ExecutionContext context,
JcrNodeTypeSource source ) {
this.context = context;
@@ -454,6 +479,52 @@
}
/**
+ * Searches the supplied primary and mixin node types for all valid property definitions that match the given property name
+ * and cardinality.
+ * <p>
+ * If no satisfactory property definition could be found, this method returns an empty list.
+ * </p>
+ *
+ * @param typeNamesToCheck the name of the types to check; may not be null
+ * @param propertyName the name of the property for which the definitions should be retrieved
+ * @param typeToCheck the type of definitions to consider (single-valued only, multi-valued only, or all)
+ * @param pendingTypes a list of types that have been created during type registration but not yet registered in the type map
+ * @return a list of all valid property definitions that match the given property name and cardinality
+ */
+ private List<JcrPropertyDefinition> findPropertyDefinitions( List<Name> typeNamesToCheck,
+ Name propertyName,
+ PropertyCardinality typeToCheck,
+ List<JcrNodeType> pendingTypes ) {
+ assert typeNamesToCheck != null;
+ Collection<JcrPropertyDefinition> propDefs = null;
+ List<JcrPropertyDefinition> matchingDefs = new ArrayList<JcrPropertyDefinition>();
+
+ // Look for a single-value property definition on the mixin types that matches by name and type ...
+ for (Name typeNameToCheck : typeNamesToCheck) {
+ JcrNodeType typeName = findTypeInMapOrList(typeNameToCheck, pendingTypes);
+ if (typeName == null) continue;
+
+ switch (typeToCheck) {
+ case SINGLE_VALUED_ONLY:
+ propDefs = typeName.allSingleValuePropertyDefinitions(propertyName);
+ break;
+ case MULTI_VALUED_ONLY:
+ propDefs = typeName.allMultiValuePropertyDefinitions(propertyName);
+ break;
+ case ANY:
+ propDefs = typeName.allPropertyDefinitions(propertyName);
+ break;
+ default:
+ throw new IllegalStateException("Should be unreachable: " + typeToCheck);
+ }
+
+ matchingDefs.addAll(propDefs);
+ }
+
+ return matchingDefs;
+ }
+
+ /**
* Determine if the property definitions of the supplied primary type and mixin types allow the property with the supplied
* name to be removed.
*
@@ -566,6 +637,50 @@
}
/**
+ * Searches the supplied primary and mixin node types for all valid child node definitions that match the given child node
+ * name and cardinality.
+ * <p>
+ * If no satisfactory child node definition could be found, this method returns an empty list.
+ * </p>
+ *
+ * @param typeNamesToCheck the name of the types to check; may not be null
+ * @param childNodeName the name of the child node for which the definitions should be retrieved
+ * @param typesToCheck the type of definitions to consider (allows SNS or does not allow SNS)
+ * @param pendingTypes a list of types that have been created during type registration but not yet registered in the type map
+ * @return a list of all valid chlid node definitions that match the given child node name and cardinality
+ */
+ private List<JcrNodeDefinition> findChildNodeDefinitions( List<Name> typeNamesToCheck,
+ Name childNodeName,
+ NodeCardinality typesToCheck,
+ List<JcrNodeType> pendingTypes ) {
+ assert typeNamesToCheck != null;
+ Collection<JcrNodeDefinition> nodeDefs = null;
+ List<JcrNodeDefinition> matchingDefs = new ArrayList<JcrNodeDefinition>();
+
+ for (Name typeNameToCheck : typeNamesToCheck) {
+ JcrNodeType typeName = findTypeInMapOrList(typeNameToCheck, pendingTypes);
+ if (typeName == null) continue;
+
+ switch (typesToCheck) {
+ case NO_SAME_NAME_SIBLINGS:
+ nodeDefs = typeName.allChildNodeDefinitions(childNodeName);
+ break;
+ case SAME_NAME_SIBLINGS:
+ nodeDefs = typeName.allChildNodeDefinitions(childNodeName, true);
+ break;
+ }
+
+ assert nodeDefs != null;
+ for (JcrNodeDefinition definition : nodeDefs) {
+ if (NodeCardinality.NO_SAME_NAME_SIBLINGS == typesToCheck && definition.allowsSameNameSiblings()) continue;
+ matchingDefs.add(definition);
+ }
+ }
+
+ return matchingDefs;
+ }
+
+ /**
* Determine if the child node definitions of the supplied primary type and mixin types of a parent node allow all of the
* children with the supplied name to be removed.
*
@@ -819,4 +934,531 @@
batch.create(nodeDefPath).with(propsList).and();
}
+
+ /**
+ * Registers the node types from the given {@link JcrNodeTypeSource}.
+ * <p>
+ * The effect of this method is "all or nothing"; if an error occurs, no node types are registered or updated.
+ * </p>
+ * <p>
+ * <b>DNA Implementation Notes</b>
+ * </p>
+ * <p>
+ * DNA currently supports registration of batches of types with some constraints. DNA will allow types to be registered if
+ * they meet the following criteria:
+ * <ol>
+ * <li>Existing types cannot be modified in-place - They must be unregistered and re-registered</li>
+ * <li>Types must have a non-null, non-empty name</li>
+ * <li>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</li>
+ * <li>Each type must have a valid set of supertypes - that is, the type's supertypes must meet the following criteria:
+ * <ol>
+ * <li>The type must have at least one supertype (unless the type is {@code nt:base}.</li>
+ * <li>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).</li>
+ * <li>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).</li>
+ * </ol>
+ * </li>
+ * <li>Each type must have a valid set of properties - that is, the type's properties must meet the following criteria:
+ * <ol>
+ * <li>Residual property definitions cannot be mandatory</li>
+ * <li>If the property is auto-created, it must specify a default value</li>
+ * <li>If the property is single-valued, it can only specify a single default value</li>
+ * <li>If the property overrides an existing property definition from a supertype, the new definition must be mandatory if the
+ * old definition was mandatory</li>
+ * <li>The property cannot override an existing property definition from a supertype if the ancestor definition is protected</li>
+ * <li>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. <i>This requirement may be relaxed in a future
+ * version of DNA.</i></li>
+ * <li>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 6.2.6 of the JCR 1.0.1 specification)</li>
+ * </ol>
+ * Note that an empty set of properties would meet the above criteria.</li>
+ * <li>The type must have a valid set of child nodes - that is, the types's child nodes must meet the following criteria:
+ * <ol>
+ * <li>Residual child node definitions cannot be mandatory</li>
+ * <li>If the child node is auto-created, it must specify a default primary type name</li>
+ * <li>All required primary types must already be fully registered with the type manager or must have been defined earlier in
+ * the batch. <i>This requirement may be relaxed in a future version of DNA.</i></li>
+ * <li>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</li>
+ * <li>The child node cannot override an existing child node definition from a supertype if the ancestor definition is
+ * protected</li>
+ * <li>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.</li>
+ * </ol>
+ * Note that an empty set of child nodes would meet the above criteria.</li>
+ * </p>
+ *
+ * @param nodeTypeSource the batch of {@link NodeType node types} to register
+ * @return the newly registered (or updated) {@link NodeType NodeTypes}
+ * @throws RepositoryException if any of the node types in the the {@link JcrNodeTypeSource} are invalid
+ * @throws RepositoryException if another error occurs
+ */
+ List<JcrNodeType> registerNodeTypes( JcrNodeTypeSource nodeTypeSource ) throws RepositoryException {
+
+ assert nodeTypeSource != null;
+ Collection<JcrNodeType> nodeTypeBatch = nodeTypeSource.getNodeTypes();
+
+ List<JcrNodeType> typesPendingRegistration = new ArrayList<JcrNodeType>(nodeTypeBatch.size());
+
+ for (JcrNodeType nodeType : nodeTypeBatch) {
+ if (nodeType.getInternalName() == null || nodeType.getName().length() == 0) {
+ throw new RepositoryException(JcrI18n.invalidNodeTypeName.text());
+ }
+
+ Name name = nodeType.getInternalName();
+
+ if (nodeTypes.containsKey(name)) {
+ throw new RepositoryException(JcrI18n.nodeTypeAlreadyExists.text(nodeType.getName()));
+ }
+
+ List<JcrNodeType> supertypes = supertypesFor(nodeType, typesPendingRegistration);
+
+ validate(nodeType, supertypes, typesPendingRegistration);
+
+ List<JcrPropertyDefinition> propertyDefs = new ArrayList<JcrPropertyDefinition>(
+ nodeType.getDeclaredPropertyDefinitions().length);
+
+ for (JcrPropertyDefinition propertyDef : nodeType.getDeclaredPropertyDefinitions()) {
+ propertyDefs.add(propertyDef.with(this.context));
+ }
+
+ List<JcrNodeDefinition> nodeDefs = new ArrayList<JcrNodeDefinition>(nodeType.getDeclaredChildNodeDefinitions().length);
+
+ for (JcrNodeDefinition nodeDef : nodeType.getDeclaredChildNodeDefinitions()) {
+ JcrNodeType[] requiredPrimaryTypes = new JcrNodeType[nodeDef.getRequiredPrimaryTypeNames().size()];
+
+ int i = 0;
+ for (Name primaryTypeName : nodeDef.getRequiredPrimaryTypeNames()) {
+ requiredPrimaryTypes[i] = findTypeInMapOrList(primaryTypeName, typesPendingRegistration);
+
+ if (requiredPrimaryTypes[i] == null) {
+ throw new RepositoryException(JcrI18n.invalidPrimaryTypeName.text(primaryTypeName, nodeType.getName()));
+ }
+ i++;
+ }
+
+ nodeDefs.add(nodeDef.with(this.context));
+ }
+
+ JcrNodeType newNodeType = new JcrNodeType(this.context, this, name, supertypes,
+ nodeType.getInternalPrimaryItemName(), nodeDefs, propertyDefs,
+ nodeType.isMixin(), nodeType.hasOrderableChildNodes());
+ typesPendingRegistration.add(newNodeType);
+ }
+
+ // 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);
+ }
+
+ // projectNodeTypeOnto(nodeType, parentOfTypeNodes, batch);
+ }
+
+ // batch.execute();
+
+ return typesPendingRegistration;
+ }
+
+ /**
+ * Finds the named type in the given list of types pending registration if it exists, else returns the type definition from
+ * the repository
+ *
+ * @param typeName the name of the type to retrieve
+ * @param pendingList a list of types that have passed validation but have not yet been committed to the repository
+ * @return the node type with the given name from {@code pendingList} if it exists in the list or from the {@link #nodeTypes
+ * registered types} if it exists there; may be null
+ */
+ private JcrNodeType findTypeInMapOrList( Name typeName,
+ List<JcrNodeType> pendingList ) {
+ for (JcrNodeType pendingNodeType : pendingList) {
+ if (pendingNodeType.getInternalName().equals(typeName)) {
+ return pendingNodeType;
+ }
+ }
+
+ return nodeTypes.get(typeName);
+ }
+
+ /**
+ * Returns the list of node types for the supertypes defined in the given node type.
+ *
+ * @param nodeType a node type with a non-null array of supertypes
+ * @param pendingTypes the list of types that have been processed in this type batch but not yet committed to the repository's
+ * set of types
+ * @return a list of node types where each element is the node type for the corresponding element of the array of supertype
+ * names
+ * @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<JcrNodeType> supertypesFor( JcrNodeType nodeType,
+ List<JcrNodeType> pendingTypes ) throws RepositoryException {
+ assert nodeType != null;
+
+ // If no supertypes are provided, assume nt:base as a supertype
+ if (nodeType.getDeclaredSupertypes() == null || nodeType.getDeclaredSupertypes().length == 0) {
+ return Collections.<JcrNodeType>singletonList(nodeTypes.get(JcrNtLexicon.BASE));
+ }
+
+ JcrNodeType[] supertypesArray = nodeType.getDeclaredSupertypes();
+ List<JcrNodeType> supertypes = new ArrayList<JcrNodeType>(supertypesArray.length);
+
+ for (int i = 0; i < supertypesArray.length; i++) {
+ supertypes.add(findTypeInMapOrList(supertypesArray[i].getInternalName(), pendingTypes));
+
+ if (supertypes.get(i) == null) {
+ throw new RepositoryException(JcrI18n.invalidSupertypeName.text(supertypesArray[i].getInternalName(),
+ nodeType.getName()));
+ }
+ }
+
+ return supertypes;
+ }
+
+ /**
+ * Validates that the supertypes are compatible under DNA restrictions.
+ * <p>
+ * DNA imposes the following rules on the supertypes of a type:
+ * <ol>
+ * <li>The type must have at least one supertype (unless the type is {@code nt:base}.</li>
+ * <li>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).</li>
+ * <li>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).</li>
+ * </ol>
+ * </p>
+ * <p>
+ * If any of these rules are violated, a {@link RepositoryException} is thrown.
+ * </p>
+ *
+ * @param supertypes the supertypes of this node type
+ * @param nodeName the name of the node for which the supertypes are being validated.
+ * @throws RepositoryException if any of the rules described above are violated
+ */
+ private void validate( List<JcrNodeType> supertypes,
+ String nodeName ) throws RepositoryException {
+ assert supertypes.size() > 0; // This is reasonable now that we default to having a supertype of nt:base
+
+ Map<JcrPropertyDefinition.Key, JcrPropertyDefinition> props = new HashMap<JcrPropertyDefinition.Key, JcrPropertyDefinition>();
+
+ for (JcrNodeType supertype : supertypes) {
+ for (JcrPropertyDefinition property : supertype.propertyDefinitions()) {
+ JcrPropertyDefinition oldProp = props.put(property.getKey(false), property);
+ if (oldProp != null) {
+ String oldPropTypeName = oldProp.getDeclaringNodeType().getName();
+ String propTypeName = property.getDeclaringNodeType().getName();
+ if (!oldPropTypeName.equals(propTypeName)) {
+ throw new RepositoryException(JcrI18n.supertypesConflict.text(oldPropTypeName,
+ propTypeName,
+ "property",
+ property.getName()));
+ }
+ }
+ }
+ }
+
+ Map<JcrNodeDefinition.Key, JcrNodeDefinition> childNodes = new HashMap<JcrNodeDefinition.Key, JcrNodeDefinition>();
+
+ for (JcrNodeType supertype : supertypes) {
+ for (JcrNodeDefinition childNode : supertype.childNodeDefinitions()) {
+ JcrNodeDefinition oldNode = childNodes.put(childNode.getKey(false), childNode);
+ if (oldNode != null) {
+ String oldNodeTypeName = oldNode.getDeclaringNodeType().getName();
+ String childNodeTypeName = childNode.getDeclaringNodeType().getName();
+ if (!oldNodeTypeName.equals(childNodeTypeName)) {
+ throw new RepositoryException(JcrI18n.supertypesConflict.text(oldNodeTypeName,
+ childNodeTypeName,
+ "child node",
+ childNode.getName()));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Validates that the given node type definition is valid under the DNA and JCR type rules within the given context.
+ * <p>
+ * See {@link #registerNodeTypes(JcrNodeTypeSource)} for the list of criteria that determine whether a node type definition is
+ * valid.
+ * </p>
+ *
+ * @param nodeType the node type to attempt to validate
+ * @param supertypes the names of the supertypes of the node type to which this child node belongs
+ * @param pendingTypes the list of types previously registered in this batch but not yet committed to the repository
+ * @throws RepositoryException if the given node type template is not valid
+ */
+ private void validate( JcrNodeType nodeType,
+ List<JcrNodeType> supertypes,
+ List<JcrNodeType> pendingTypes ) throws RepositoryException {
+ validate(supertypes, nodeType.getName());
+
+ List<Name> supertypeNames = new ArrayList<Name>(supertypes.size());
+ for (JcrNodeType supertype : supertypes)
+ supertypeNames.add(supertype.getInternalName());
+
+ boolean found = false;
+ String primaryItemName = nodeType.getPrimaryItemName();
+ for (JcrNodeDefinition node : nodeType.getDeclaredChildNodeDefinitions()) {
+ validate(node, supertypeNames, pendingTypes);
+
+ if (primaryItemName != null && primaryItemName.equals(node.getName())) {
+ found = true;
+ }
+ }
+
+ for (JcrPropertyDefinition prop : nodeType.getDeclaredPropertyDefinitions()) {
+ validate(prop, supertypeNames, pendingTypes);
+ if (primaryItemName != null && primaryItemName.equals(prop.getName())) {
+ if (found) {
+ throw new RepositoryException(JcrI18n.ambiguousPrimaryItemName.text(primaryItemName));
+ }
+ found = true;
+ }
+ }
+
+ if (primaryItemName != null && !found) {
+ throw new RepositoryException(JcrI18n.invalidPrimaryItemName.text(primaryItemName));
+ }
+ }
+
+ /**
+ * Validates that the given child node definition is valid under the DNA and JCR type rules within the given context.
+ * <p>
+ * DNA considers a child node definition valid if it meets these criteria:
+ * <ol>
+ * <li>Residual child node definitions cannot be mandatory</li>
+ * <li>If the child node is auto-created, it must specify a default primary type name</li>
+ * <li>All required primary types must already be fully registered with the type manager or must have been defined earlier in
+ * the batch. This requirement may be relaxed in a future version of DNA.</li>
+ * <li>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</li>
+ * <li>The child node cannot override an existing child node definition from a supertype if the ancestor definition is
+ * protected</li>
+ * <li>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.</li>
+ * </ol>
+ * </p>
+ *
+ * @param node the child node definition to be validated
+ * @param supertypes the names of the supertypes of the node type to which this child node belongs
+ * @param pendingTypes the list of types previously registered in this batch but not yet committed to the repository
+ * @throws RepositoryException if the child node definition is not valid
+ */
+ private void validate( JcrNodeDefinition node,
+ List<Name> supertypes,
+ List<JcrNodeType> pendingTypes ) throws RepositoryException {
+ if (node.isAutoCreated() && node.getDefaultPrimaryType() == null) {
+ throw new RepositoryException(JcrI18n.autocreatedNodesNeedDefaults.text());
+ }
+ if (node.isMandatory() && node.getName() == null) {
+ throw new RepositoryException(JcrI18n.residualDefinitionsCannotBeMandatory.text("child nodes"));
+ }
+
+ Name nodeName = context.getValueFactories().getNameFactory().create(node.getName());
+ nodeName = nodeName == null ? JcrNodeType.RESIDUAL_NAME : nodeName;
+
+ List<JcrNodeDefinition> ancestors = findChildNodeDefinitions(supertypes,
+ nodeName,
+ node.allowsSameNameSiblings() ? NodeCardinality.SAME_NAME_SIBLINGS : NodeCardinality.NO_SAME_NAME_SIBLINGS,
+ pendingTypes);
+
+ for (JcrNodeDefinition ancestor : ancestors) {
+ if (ancestor.isProtected()) {
+ throw new RepositoryException(
+ JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType().getName(),
+ "child node"));
+ }
+
+ if (ancestor.isMandatory() && !node.isMandatory()) {
+ throw new RepositoryException(
+ JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType().getName(),
+ "child node"));
+
+ }
+
+ for (int i = 0; i < ancestor.getRequiredPrimaryTypes().length; i++) {
+ NodeType apt = ancestor.getRequiredPrimaryTypes()[i];
+ boolean found = false;
+ for (Name name : node.getRequiredPrimaryTypeNames()) {
+ JcrNodeType npt = findTypeInMapOrList(name, pendingTypes);
+
+ if (npt.isNodeType(apt.getName())) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new RepositoryException(
+ "Cannot redefine child node '"
+ + nodeName
+ + "' with required type '"
+ + apt.getName()
+ + "' with new child node that does not required that type or a subtype of that type.");
+
+ }
+ }
+ }
+ }
+
+ /**
+ * Validates that the given property definition is valid under the DNA and JCR type rules within the given context.
+ * <p>
+ * DNA considers a property definition valid if it meets these criteria:
+ * <ol>
+ * <li>Residual properties cannot be mandatory</li>
+ * <li>If the property is auto-created, it must specify a default value</li>
+ * <li>If the property is single-valued, it can only specify a single default value</li>
+ * <li>If the property overrides an existing property definition from a supertype, the new definition must be mandatory if the
+ * old definition was mandatory</li>
+ * <li>The property cannot override an existing property definition from a supertype if the ancestor definition is protected</li>
+ * <li>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 6.2.6 of the JCR 1.0.1 specification)</li>
+ * </ol>
+ * Note that an empty set of properties would meet the criteria above.
+ * </p>
+ *
+ * @param prop the property definition to be validated
+ * @param supertypes the names of the supertypes of the node type to which this property belongs
+ * @param pendingTypes the list of types previously registered in this batch but not yet committed to the repository
+ * @throws RepositoryException if the property definition is not valid
+ */
+ private void validate( JcrPropertyDefinition prop,
+ List<Name> supertypes,
+ List<JcrNodeType> pendingTypes ) throws RepositoryException {
+ assert prop != null;
+ assert supertypes != null;
+ assert pendingTypes != null;
+
+ if (prop.isMandatory() && !prop.isProtected() && prop.getName() == null) {
+ throw new RepositoryException(JcrI18n.residualDefinitionsCannotBeMandatory.text("properties"));
+ }
+
+ Value[] defaultValues = prop.getDefaultValues();
+ if (prop.isAutoCreated() && !prop.isProtected() && (defaultValues == null || defaultValues.length == 0)) {
+ throw new RepositoryException(JcrI18n.autocreatedPropertyNeedsDefault.text(prop.getName(),
+ prop.getDeclaringNodeType().getName()));
+ }
+
+ if (!prop.isMultiple() && (defaultValues != null && defaultValues.length > 1)) {
+ throw new RepositoryException(
+ JcrI18n.singleValuedPropertyNeedsSingleValuedDefault.text(prop.getName(),
+ prop.getDeclaringNodeType().getName()));
+ }
+
+ Name propName = context.getValueFactories().getNameFactory().create(prop.getName());
+ propName = propName == null ? JcrNodeType.RESIDUAL_NAME : propName;
+
+ List<JcrPropertyDefinition> ancestors = findPropertyDefinitions(supertypes,
+ propName,
+ prop.isMultiple() ? PropertyCardinality.MULTI_VALUED_ONLY : PropertyCardinality.SINGLE_VALUED_ONLY,
+ pendingTypes);
+
+ for (JcrPropertyDefinition ancestor : ancestors) {
+ if (ancestor.isProtected()) {
+ throw new RepositoryException(
+ JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType().getName(),
+ "property"));
+ }
+
+ if (ancestor.isMandatory() && !prop.isMandatory()) {
+ throw new RepositoryException(
+ JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType().getName(),
+ "property"));
+
+ }
+
+ // TODO: It would be nice if we could allow modification of constraints if the new constraints were more strict than
+ // the old
+ if (ancestor.getValueConstraints() != null
+ && !Arrays.equals(ancestor.getValueConstraints(), prop.getValueConstraints())) {
+ throw new RepositoryException(JcrI18n.constraintsChangedInSubtype.text(propName,
+ ancestor.getDeclaringNodeType().getName()));
+ }
+
+ if (!isAlwaysSafeConversion(prop.getRequiredType(), ancestor.getRequiredType())) {
+ throw new RepositoryException(
+ JcrI18n.cannotRedefineProperty.text(propName,
+ PropertyType.nameFromValue(prop.getRequiredType()),
+ ancestor.getDeclaringNodeType().getName(),
+ PropertyType.nameFromValue(ancestor.getRequiredType())));
+
+ }
+ }
+ }
+
+ /**
+ * Returns whether it is always possible to convert a value with JCR property type {@code fromType} to {@code toType}.
+ * <p>
+ * This method is based on the conversions which can never throw an exception in the chart in section 6.2.6 of the JCR 1.0.1
+ * specification.
+ * </p>
+ *
+ * @param fromType the type to be converted from
+ * @param toType the type to convert to
+ * @return true if any value with type {@code fromType} can be converted to a type of {@code toType} without a
+ * {@link ValueFormatException} being thrown.
+ * @see PropertyType
+ */
+ private boolean isAlwaysSafeConversion( int fromType,
+ int toType ) {
+
+ if (fromType == toType) return true;
+
+ switch (toType) {
+ case PropertyType.BOOLEAN:
+ return fromType == PropertyType.BINARY || fromType == PropertyType.STRING;
+
+ case PropertyType.DATE:
+ return fromType == PropertyType.DOUBLE || fromType == PropertyType.LONG;
+
+ case PropertyType.DOUBLE:
+ // Conversion from DATE could result in out-of-range value
+ return fromType == PropertyType.LONG;
+ case PropertyType.LONG:
+ // Conversion from DATE could result in out-of-range value
+ return fromType == PropertyType.DOUBLE;
+
+ case PropertyType.PATH:
+ return fromType == PropertyType.NAME;
+
+ // Values of any type MAY fail when converting to these types
+ case PropertyType.NAME:
+ case PropertyType.REFERENCE:
+ return false;
+
+ // Any type can be converted to these types
+ case PropertyType.BINARY:
+ case PropertyType.STRING:
+ case PropertyType.UNDEFINED:
+ return true;
+
+ default:
+ throw new IllegalStateException("Unexpected state: " + toType);
+ }
+ }
+
}
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-04-13 19:29:46 UTC (rev 819)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-04-14 16:13:03 UTC (rev 820)
@@ -66,6 +66,7 @@
errorWhileFindingNodeWithUuid = Error while finding the node with UUID "{0}" in workspace "{1}": {2}
errorWhileFindingNodeWithPath = Error while finding the node "{0}" in workspace "{1}"
nodeDefinitionCouldNotBeDeterminedForNode = Unable to determine a valid node definition for the node "{0}" in workspace "{1}"
+noSnsDefinitionForNode = A node definition that allows same name siblings could not be found for the node "{0}" in workspace "{1}"
missingNodeTypeForExistingNode = Missing primary node type "{0}" for node {1} in workspace "{2}"
unableToCreateNodeWithPrimaryTypeThatDoesNotExist = Unable to create child "{1}" in workspace "{2}" because the node type "{0}" does not exist
unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition = Unable to create child "{2}" in workspace "{3}" because the node definition "{0}" on the "{1}" node type has no default primary type
@@ -93,4 +94,20 @@
tooDeep=Depth parameter ({0}) cannot be greater than the result of getDepth() for this node
notStoredQuery=This query has not been stored or loaded
-invalidQueryLanguage="{0}" is not a valid query langauge. Supported languages are: {1}
\ No newline at end of file
+invalidQueryLanguage="{0}" is not a valid query langauge. Supported languages are\: {1}
+
+invalidNodeTypeName=Node types cannot have a null or empty name
+nodeTypeAlreadyExists=Node type '{0}' already exists
+invalidPrimaryTypeName=Required primary type '{0}' in type '{1}' does not exist
+invalidSupertypeName=Supertype '{0}' from type '{1}' does not exist
+supertypesConflict=Types '{0}' and '{1}' cannot both be supertypes of the same type, as both separately declare {2} '{3}'
+ambiguousPrimaryItemName=Primary item name '{0}' matches the name of a child node and a property
+invalidPrimaryItemName=Primary item name '{0}' does not match the name of any child nodes or properties
+autocreatedNodesNeedDefaults=Autocreated child nodes must specify a default primary type
+residualDefinitionsCannotBeMandatory=Residual {0} cannot be mandatory
+cannotOverrideProtectedDefinition=Cannot override protected {1} definition from '{0}'
+cannotMakeMandatoryDefinitionOptional=Cannot override mandatory {1} definition from '{0}' with a non-mandatory definition.
+constraintsChangedInSubtype=Must use exact same constraints when overriding the property definition for {0} from type '{1}'
+cannotRedefineProperty=Cannot redefine property '{0}' with new type '{1}' when existing property with same name in type '{2}' has incompatible type '{3}'
+autocreatedPropertyNeedsDefault=Auto-created property '{0}' in type '{1}' must specify a default value
+singleValuedPropertyNeedsSingleValuedDefault=Single-valued property '{0}' in type '{1}' cannot have multiple default values
17 years