Author: rhauch
Date: 2009-03-06 11:51:55 -0500 (Fri, 06 Mar 2009)
New Revision: 761
Added:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.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/resources/org/jboss/dna/jcr/JcrI18n.properties
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
Log:
DNA-194 Implement update JCR capability
None of the nodes had a Node.getDefinition() implementation. To properly implement this,
I refactored how JcrSession was creating and populating nodes, and I added some utility
methods to the JcrNodeTypeManager (which is now a separate package-protected class rather
than an inner class).
This allows all of the Level 2 TCK unit tests to get further, but none of the other update
functionality is implemented, so none of the Level 2 TCK tests run successfully.
I also made a number of utility methods final, in the hopes that they can be inlined since
they are called very frequently.
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-03-05 18:20:33
UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-03-06 16:51:55
UTC (rev 761)
@@ -71,10 +71,14 @@
Map<Name, Property> properties;
List<Path.Segment> children;
private UUID uuid;
+ private final NodeDefinition definition;
- AbstractJcrNode( JcrSession session ) {
+ AbstractJcrNode( JcrSession session,
+ NodeDefinition definition ) {
assert session != null;
+ assert definition != null;
this.session = session;
+ this.definition = definition;
}
/**
@@ -112,26 +116,33 @@
this.properties = properties;
}
+ /**
+ * Utility mehtod to create a {@link Name} from the supplied string.
+ *
+ * @param name the string
+ * @return the name, or null if the supplied string is null
+ */
final Name nameFrom( String name ) {
return
session.getExecutionContext().getValueFactories().getNameFactory().create(name);
}
+ final NamespaceRegistry namespaces() {
+ return session.getExecutionContext().getNamespaceRegistry();
+ }
+
/**
* {@inheritDoc}
*
* @see javax.jcr.Node#getUUID()
*/
public final String getUUID() throws RepositoryException {
- // Return JCR UUID only if node is referenceable
- try {
- Property mixinsProp = getProperty("jcr:mixinTypes");
- if (mixinsProp != null) {
- for (Value value : mixinsProp.getValues()) {
- if ("mix:referenceable".equals(value.getString())) return
getProperty("jcr:uuid").getString();
- }
+ // Return "jcr:uuid" only if node is referenceable
+ Property mixinsProp = getProperty(JcrLexicon.MIXIN_TYPES);
+ if (mixinsProp != null) {
+ String referenceableMixinName =
JcrMixLexicon.REFERENCEABLE.getString(namespaces());
+ for (Value value : mixinsProp.getValues()) {
+ if (referenceableMixinName.equals(value.getString())) return
getProperty(JcrLexicon.UUID).getString();
}
- } catch (PathNotFoundException error) {
- throw new UnsupportedRepositoryOperationException(error);
}
throw new UnsupportedRepositoryOperationException();
}
@@ -175,7 +186,7 @@
* @see javax.jcr.Node#getDefinition()
*/
public NodeDefinition getDefinition() {
- return null;
+ return definition;
}
/**
@@ -443,7 +454,7 @@
if (children == null) {
return new JcrEmptyNodeIterator();
}
- return new JcrChildNodeIterator(this,
this.session.getExecutionContext().getNamespaceRegistry(), children);
+ return new JcrChildNodeIterator(this, namespaces(), children);
}
/**
@@ -461,7 +472,7 @@
// Implementing exact-matching only for now to prototype types as properties
List<Path.Segment> matchingChildren = new
LinkedList<Path.Segment>();
- NamespaceRegistry registry = session.executionContext.getNamespaceRegistry();
+ NamespaceRegistry registry = namespaces();
boolean foundMatch = false;
for (Path.Segment child : children) {
String childName = child.getName().getString(registry);
@@ -480,7 +491,7 @@
}
}
}
- return new JcrChildNodeIterator(this,
this.session.executionContext.getNamespaceRegistry(), matchingChildren);
+ return new JcrChildNodeIterator(this, registry, matchingChildren);
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -34,5 +34,6 @@
public static final Name NAMESPACES = new BasicName(Namespace.URI,
"namespaces");
public static final Name NAMESPACE = new BasicName(Namespace.URI,
"namespace");
public static final Name URI = new BasicName(Namespace.URI, "uri");
+ public static final Name NODE_DEFINITON = new BasicName(Namespace.URI,
"nodeDefinition");
}
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-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -63,6 +63,7 @@
public static I18n invalidNamePattern;
public static I18n itemNotFoundWithUuid;
public static I18n errorWhileFindingNodeWithUuid;
+ public static I18n nodeDefinitionCouldBeDeterminedForNode;
public static I18n typeNotFound;
public static I18n supertypeNotFound;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -27,6 +27,7 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinition;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.graph.property.Path.Segment;
@@ -41,8 +42,9 @@
JcrNode( JcrSession session,
UUID parentUuid,
- Segment segment ) {
- super(session);
+ Segment segment,
+ NodeDefinition nodeDefinition ) {
+ super(session, nodeDefinition);
assert parentUuid != null;
assert segment != null;
this.parentUuid = parentUuid;
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-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -150,6 +150,33 @@
}
/**
+ * Determine the best (most specific) {@link NodeDefinition} for a child with the
supplied name and primary type. If the
+ * primary type is not supplied, then only the name is considered when finding a best
match.
+ *
+ * @param childName the name of the child
+ * @param primaryNodeTypeName the name of the primary node type for the child
+ * @return the {@link NodeDefinition} that best matches the child, or null if a child
with the supplied name and primary type
+ * are not allowed given this node type
+ */
+ JcrNodeDefinition findBestNodeDefinitionForChild( String childName,
+ String primaryNodeTypeName ) {
+ // First, try to find a child node definition with the given name
+ JcrNodeDefinition childNode = getChildNodeDefinition(childName);
+
+ // If there are no named definitions in the type hierarchy, try to find a
residual node definition
+ if (childNode == null) {
+ childNode = getChildNodeDefinition(RESIDUAL_ITEM_NAME);
+ }
+
+ // Check if the node can be added with the named child node definition
+ if (childNode != null && primaryNodeTypeName != null) {
+ NodeType primaryNodeType = getPrimaryNodeType(primaryNodeTypeName);
+ if (!checkTypeAgainstDefinition(primaryNodeType, childNode)) return null;
+ }
+ return childNode;
+ }
+
+ /**
* {@inheritDoc}
*
* @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String)
@@ -179,6 +206,15 @@
return false;
}
+ protected final NodeType getPrimaryNodeType( String primaryNodeTypeName ) {
+ try {
+ return
session.getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName);
+ } catch (RepositoryException re) {
+ // If the node type doesn't exist, you can't add a child node with
that type
+ return null;
+ }
+ }
+
/**
* {@inheritDoc}
*
@@ -190,11 +226,9 @@
CheckArg.isNotNull(childNodeName, "childNodeName");
CheckArg.isNotNull(primaryNodeTypeName, "primaryNodeTypeName");
- NodeType primaryNodeType;
- try {
- primaryNodeType =
session.getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName);
- } catch (RepositoryException re) {
- // If the node type doesn't exist, you can't add a child node with
that type
+ NodeType primaryNodeType = getPrimaryNodeType(primaryNodeTypeName);
+ if (primaryNodeType == null) {
+ // The node type doesn't exist, so you can't add a child node with
that type
return false;
}
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-03-06
16:51:55 UTC (rev 761)
@@ -0,0 +1,145 @@
+/*
+ * 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.jcr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.property.Name;
+
+/**
+ * Local implementation of @{link NodeTypeManager}. Initialized with {@link NodeType}
source data when it is created (in the
+ * {@link JcrWorkspace} constructor.
+ */
+@NotThreadSafe
+class JcrNodeTypeManager implements NodeTypeManager {
+
+ private final Map<Name, JcrNodeType> primaryNodeTypes;
+ private final Map<Name, JcrNodeType> mixinNodeTypes;
+ private final JcrSession session;
+
+ JcrNodeTypeManager( JcrSession session,
+ JcrNodeTypeSource source ) {
+ this.session = session;
+ Collection<JcrNodeType> primary = source.getPrimaryNodeTypes();
+ Collection<JcrNodeType> mixins = source.getMixinNodeTypes();
+
+ primaryNodeTypes = new HashMap<Name, JcrNodeType>(primary.size());
+ for (JcrNodeType nodeType : primary) {
+ primaryNodeTypes.put(nodeType.getInternalName(), nodeType);
+ }
+
+ mixinNodeTypes = new HashMap<Name, JcrNodeType>(mixins.size());
+ for (JcrNodeType nodeType : mixins) {
+ mixinNodeTypes.put(nodeType.getInternalName(), nodeType);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see javax.jcr.nodetype.NodeTypeManager#getAllNodeTypes()
+ */
+ public NodeTypeIterator getAllNodeTypes() {
+
+ // TODO: Can revisit this approach later if it becomes a performance issue
+ /*
+ * Note also that this creates a subtle difference in behavior for concurrent
modification
+ * between this method and the specific get*NodeTypes methods. That is, if a
type is added
+ * while an iterator from the corresponding specific get*NodeType method is being
traversed,
+ * a ConcurrentModificationException will be thrown. Because this iterator is
based on a copy
+ * of the underlying maps, no exception would be thrown in the same case.
+ */
+
+ List<NodeType> allTypes = new
ArrayList<NodeType>(primaryNodeTypes.size() + mixinNodeTypes.size());
+ allTypes.addAll(primaryNodeTypes.values());
+ allTypes.addAll(mixinNodeTypes.values());
+ return new JcrNodeTypeIterator(allTypes);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see javax.jcr.nodetype.NodeTypeManager#getMixinNodeTypes()
+ */
+ public NodeTypeIterator getMixinNodeTypes() {
+ return new JcrNodeTypeIterator(mixinNodeTypes.values());
+ }
+
+ final JcrNodeType getNodeType( Name nodeTypeName ) {
+
+ JcrNodeType nodeType = primaryNodeTypes.get(nodeTypeName);
+ if (nodeType == null) {
+ nodeType = mixinNodeTypes.get(nodeTypeName);
+ }
+ return nodeType;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see javax.jcr.nodetype.NodeTypeManager#getNodeType(java.lang.String)
+ */
+ public NodeType getNodeType( String nodeTypeName ) throws NoSuchNodeTypeException,
RepositoryException {
+ Name ntName =
session.getExecutionContext().getValueFactories().getNameFactory().create(nodeTypeName);
+ NodeType type = getNodeType(ntName);
+ if (type != null) return type;
+ throw new NoSuchNodeTypeException(JcrI18n.typeNotFound.text(nodeTypeName));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see javax.jcr.nodetype.NodeTypeManager#getPrimaryNodeTypes()
+ */
+ public NodeTypeIterator getPrimaryNodeTypes() {
+ return new JcrNodeTypeIterator(primaryNodeTypes.values());
+ }
+
+ /**
+ * Get the {@link NodeDefinition} for the root node.
+ *
+ * @return the definition; never null
+ * @throws RepositoryException
+ * @throws NoSuchNodeTypeException
+ */
+ JcrNodeDefinition getRootNodeDefinition() throws NoSuchNodeTypeException,
RepositoryException {
+ // TODO: Fix this
+ for (NodeDefinition definition :
getNodeType("nt:unstructured").getChildNodeDefinitions()) {
+ if (definition.getName().equals(JcrNodeType.RESIDUAL_ITEM_NAME)) return
(JcrNodeDefinition)definition;
+ }
+ assert false; // should not get here
+ return null;
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -25,6 +25,7 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
+import javax.jcr.nodetype.NodeDefinition;
import net.jcip.annotations.NotThreadSafe;
/**
@@ -33,8 +34,9 @@
@NotThreadSafe
final class JcrRootNode extends AbstractJcrNode {
- JcrRootNode( JcrSession session ) {
- super(session);
+ JcrRootNode( JcrSession session,
+ NodeDefinition nodeDefinition ) {
+ super(session, nodeDefinition);
}
/**
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-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -51,6 +51,7 @@
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.PropertyDefinition;
@@ -59,9 +60,10 @@
import javax.security.auth.login.LoginException;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.util.CheckArg;
-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.connector.RepositorySourceException;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.graph.property.NamespaceRegistry;
@@ -123,8 +125,9 @@
private final ReferenceMap<UUID, Node> nodesByUuid;
private final ReferenceMap<String, Node> nodesByJcrUuid;
private boolean isLive;
- private JcrRootNode rootNode;
+ private AbstractJcrNode rootNode;
private PropertyDefinition anyMultiplePropertyDefinition;
+ private transient org.jboss.dna.graph.property.Property defaultPrimaryType;
JcrSession( JcrRepository repository,
JcrWorkspace workspace,
@@ -165,6 +168,14 @@
return this.executionContext;
}
+ final JcrNodeTypeManager nodeTypeManager() {
+ return this.workspace.nodeTypeManager();
+ }
+
+ final NamespaceRegistry namespaces() {
+ return this.executionContext.getNamespaceRegistry();
+ }
+
/**
* Return an unmodifiable map of nodes given then UUID.
*
@@ -369,7 +380,7 @@
Path parentPath = path.getParent();
Name propertyName = path.getLastSegment().getName();
try {
- return
getNode(parentPath).getProperty(propertyName.getString(executionContext.getNamespaceRegistry()));
+ return
getNode(parentPath).getProperty(propertyName.getString(namespaces()));
} catch (org.jboss.dna.graph.property.PathNotFoundException e2) {
// If the node isn't found, throw a PathNotFoundException
throw new PathNotFoundException(JcrI18n.pathNotFound.text(path));
@@ -387,25 +398,138 @@
throw new UnsupportedOperationException();
}
+ /**
+ * Find or create a JCR Node for the given path. This method works for the root node,
too.
+ *
+ * @param path the path; may not be null
+ * @return the JCR node instance for the given path; never null
+ * @throws RepositoryException if there is a problem
+ */
private Node getNode( Path path ) throws RepositoryException {
- // Get node from source
+ boolean isRoot = path.isRoot();
+ if (isRoot && rootNode != null) return rootNode;
+
+ // Get node from source and get it's UUID ...
org.jboss.dna.graph.Node graphNode = graph.getNodeAt(path);
- // First check if node already exists. We don't need to check for changes
since that will be handled by an observer
- org.jboss.dna.graph.property.Property dnaUuidProp =
graphNode.getPropertiesByName().get(JcrLexicon.UUID);
- if (dnaUuidProp == null) dnaUuidProp =
graphNode.getPropertiesByName().get(DnaLexicon.UUID);
- if (dnaUuidProp != null) {
- UUID uuid =
executionContext.getValueFactories().getUuidFactory().create(dnaUuidProp.getValues()).next();
+
+ // Now get the DNA node's UUID ...
+ Location location = graphNode.getLocation();
+ ValueFactories factories = executionContext.getValueFactories();
+ UUID uuid = location.getUuid();
+ org.jboss.dna.graph.property.Property uuidProperty = null;
+ if (uuid != null) {
+ // Considered an identification property ...
+ uuidProperty = location.getIdProperty(JcrLexicon.UUID);
+ if (uuidProperty == null) uuidProperty =
location.getIdProperty(DnaLexicon.UUID);
+ }
+ if (uuidProperty == null) {
+ uuidProperty = graphNode.getProperty(JcrLexicon.UUID);
+ if (uuidProperty != null) {
+ // Grab the first 'good' UUID value ...
+ for (Object uuidValue : uuidProperty) {
+ try {
+ uuid = factories.getUuidFactory().create(uuidValue);
+ break;
+ } catch (ValueFormatException e) {
+ // Ignore; just continue with the next property value
+ }
+ }
+ }
+ if (uuid == null) {
+ // Look for the DNA UUID property ...
+ org.jboss.dna.graph.property.Property dnaUuidProperty =
graphNode.getProperty(DnaLexicon.UUID);
+ if (dnaUuidProperty != null) {
+ // Grab the first 'good' UUID value ...
+ for (Object uuidValue : dnaUuidProperty) {
+ try {
+ uuid = factories.getUuidFactory().create(uuidValue);
+ break;
+ } catch (ValueFormatException e) {
+ // Ignore; just continue with the next property value
+ }
+ }
+ }
+ }
+ }
+ if (uuid == null) uuid = UUID.randomUUID();
+ if (uuidProperty == null) uuidProperty =
executionContext.getPropertyFactory().create(JcrLexicon.UUID, uuid);
+
+ // See if there is already a JCR node object for this UUID ...
+ if (uuid != null && !isRoot) {
Node node = getNode(uuid);
- if (node != null) {
- return node;
+ if (node != null) return node;
+ }
+
+ // Either the UUID is not known, or there was no node. Either way, we have to
create the node ...
+ if (uuid == null) uuid = UUID.randomUUID();
+
+ // Look for the primary type of the node ...
+ String primaryTypeNameString = null;
+ NamespaceRegistry namespaces = namespaces();
+ org.jboss.dna.graph.property.Property primaryTypeProperty =
graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
+ if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
+ Name primaryTypeName =
factories.getNameFactory().create(primaryTypeProperty.getFirstValue());
+ primaryTypeNameString = primaryTypeName.getString(namespaces);
+ } else {
+ // We have to have a primary type, so use the default ...
+ if (defaultPrimaryType == null) {
+ defaultPrimaryType =
executionContext.getPropertyFactory().create(JcrLexicon.PRIMARY_TYPE,
+
JcrNtLexicon.UNSTRUCTURED);
}
+ primaryTypeProperty = defaultPrimaryType;
+ // We have to add this property to the graph node...
+ graphNode.getPropertiesByName().put(primaryTypeProperty.getName(),
primaryTypeProperty);
}
- // If not create a new one & populate it
- JcrNode node;
- Path parentPath = path.getParent();
- if (parentPath.isRoot()) node = new JcrNode(this,
((JcrRootNode)getRootNode()).internalUuid(), path.getLastSegment());
- else node = new JcrNode(this, ((JcrNode)getNode(parentPath)).internalUuid(),
path.getLastSegment());
- populateNode(node, graphNode);
+ assert primaryTypeProperty.isEmpty() == false;
+
+ // Look for a node definition stored on the node ...
+ NodeDefinition definition = null;
+ org.jboss.dna.graph.property.Property nodeDefnProperty =
graphNode.getProperty(DnaLexicon.NODE_DEFINITON);
+ if (nodeDefnProperty != null && !nodeDefnProperty.isEmpty()) {
+ Path nodeDefnPath =
factories.getPathFactory().create(nodeDefnProperty.getFirstValue());
+ // Look up the node definition ...
+ Name nodeTypeName = nodeDefnPath.getSegment(0).getName();
+ JcrNodeType nodeType = nodeTypeManager().getNodeType(nodeTypeName);
+ if (nodeType != null && nodeDefnPath.size() > 1) {
+ // Look up the definition for the child name rule (in the second segment
of the relative path) ...
+ String childNameRule = nodeDefnPath.getSegment(1).getString(namespaces);
+ definition = nodeType.findBestNodeDefinitionForChild(childNameRule,
primaryTypeNameString);
+ }
+ }
+
+ AbstractJcrNode node = null;
+ if (isRoot) {
+ // The node definition should be set ...
+ if (definition == null) {
+ definition = nodeTypeManager().getRootNodeDefinition();
+ assert definition != null;
+ }
+
+ // Create the new node ...
+ node = new JcrRootNode(this, definition);
+ } else {
+ // Find the parent ...
+ AbstractJcrNode parent = (AbstractJcrNode)getNode(path.getParent());
+
+ // Find the node definition for this node ...
+ if (definition == null) {
+ // Look for the parent's node type, and look for a node definition
based upon the name ...
+ JcrNodeType nodeType = (JcrNodeType)parent.getPrimaryNodeType();
+ String childName =
path.getLastSegment().getName().getString(namespaces);
+ definition = nodeType.findBestNodeDefinitionForChild(childName,
primaryTypeNameString);
+ if (definition == null) {
+ String msg =
JcrI18n.nodeDefinitionCouldBeDeterminedForNode.text(path, workspace.getName());
+ throw new RepositorySourceException(msg);
+ }
+ }
+
+ // Now create the node object ...
+ node = new JcrNode(this, parent.internalUuid(), path.getLastSegment(),
definition);
+ }
+
+ // Now populate the node and add to the cache ...
+ populateNode(node, graphNode, uuid, uuidProperty, primaryTypeProperty);
+ if (isRoot) rootNode = node;
return node;
}
@@ -443,21 +567,7 @@
if (rootNode != null) {
return rootNode;
}
- // Get root node from source
- assert executionContext.getValueFactories() != null;
- assert executionContext.getValueFactories().getPathFactory() != null;
- rootNode = new JcrRootNode(this);
-
- // Get root node from source
- Path rootPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
- org.jboss.dna.graph.Node dnaRootNode = graph.getNodeAt(rootPath);
- if (dnaRootNode.getProperty(JcrLexicon.PRIMARY_TYPE) == null) {
- // Add the primary type and update the source ...
- graph.set(JcrLexicon.PRIMARY_TYPE).to(JcrNtLexicon.BASE).on(rootPath);
- dnaRootNode = graph.getNodeAt(rootPath);
- }
- populateNode(rootNode, dnaRootNode);
- return rootNode;
+ return
getNode(executionContext.getValueFactories().getPathFactory().createRootPath());
}
/**
@@ -653,10 +763,16 @@
return PropertyType.UNDEFINED;
}
- private void populateNode( AbstractJcrNode node,
- org.jboss.dna.graph.Node graphNode ) throws
RepositoryException {
+ final void populateNode( AbstractJcrNode node,
+ org.jboss.dna.graph.Node graphNode,
+ UUID uuid,
+ org.jboss.dna.graph.property.Property uuidProperty,
+ org.jboss.dna.graph.property.Property primaryTypeProperty )
throws RepositoryException {
assert node != null;
assert graphNode != null;
+ assert uuid != null;
+ assert uuidProperty != null;
+ assert primaryTypeProperty != null;
// --------------------------------------------------
// Create JCR children for corresponding DNA children
@@ -670,35 +786,34 @@
Map<Name, PropertyDefinition> propertyDefinitionsByPropertyName = new
HashMap<Name, PropertyDefinition>();
boolean referenceable = false;
- NamespaceRegistry registry = executionContext.getNamespaceRegistry();
+ NamespaceRegistry registry = namespaces();
ValueFactories factories = executionContext.getValueFactories();
NameFactory nameFactory = factories.getNameFactory();
NodeTypeManager nodeTypeManager = getWorkspace().getNodeTypeManager();
List<PropertyDefinition> anyPropertyDefinitions = new
LinkedList<PropertyDefinition>();
- org.jboss.dna.graph.property.Property primaryTypeProperty =
graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
- if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
- Name primaryTypeName =
nameFactory.create(primaryTypeProperty.getFirstValue());
- String primaryTypeNameString = primaryTypeName.getString(registry);
- NodeType primaryType = nodeTypeManager.getNodeType(primaryTypeNameString);
- for (PropertyDefinition propertyDefn : primaryType.getPropertyDefinitions())
{
- String nameString = propertyDefn.getName();
- if ("*".equals(nameString)) {
- anyPropertyDefinitions.add(propertyDefn);
- continue;
- }
- Name name = nameFactory.create(nameString);
- PropertyDefinition prev = propertyDefinitionsByPropertyName.put(name,
propertyDefn);
- if (prev != null) propertyDefinitionsByPropertyName.put(name, prev); //
put the first one back ...
+ // Start with the primary type ...
+ Name primaryTypeName = nameFactory.create(primaryTypeProperty.getFirstValue());
+ String primaryTypeNameString = primaryTypeName.getString(registry);
+ NodeType primaryType = nodeTypeManager.getNodeType(primaryTypeNameString);
+ for (PropertyDefinition propertyDefn : primaryType.getPropertyDefinitions()) {
+ String nameString = propertyDefn.getName();
+ if ("*".equals(nameString)) {
+ anyPropertyDefinitions.add(propertyDefn);
+ continue;
}
+ Name name = nameFactory.create(nameString);
+ PropertyDefinition prev = propertyDefinitionsByPropertyName.put(name,
propertyDefn);
+ if (prev != null) propertyDefinitionsByPropertyName.put(name, prev); // put
the first one back ...
}
+ // The process the mixin types ...
org.jboss.dna.graph.property.Property mixinTypesProperty =
graphNode.getProperty(JcrLexicon.MIXIN_TYPES);
if (mixinTypesProperty != null && !mixinTypesProperty.isEmpty()) {
for (Object mixinTypeValue : mixinTypesProperty) {
Name mixinTypeName = nameFactory.create(mixinTypeValue);
if (!referenceable &&
JcrMixLexicon.REFERENCEABLE.equals(mixinTypeName)) referenceable = true;
String mixinTypeNameString = mixinTypeName.getString(registry);
- NodeType primaryType = nodeTypeManager.getNodeType(mixinTypeNameString);
- for (PropertyDefinition propertyDefn :
primaryType.getPropertyDefinitions()) {
+ NodeType mixinType = nodeTypeManager.getNodeType(mixinTypeNameString);
+ for (PropertyDefinition propertyDefn :
mixinType.getPropertyDefinitions()) {
String nameString = propertyDefn.getName();
if ("*".equals(nameString)) {
anyPropertyDefinitions.add(propertyDefn);
@@ -711,45 +826,9 @@
}
}
- // Look for the UUID property ...
- UUID uuid = null;
- org.jboss.dna.graph.property.Property uuidProperty =
graphNode.getProperty(JcrLexicon.UUID);
- Name jcrUuidPropertyName = null;
- Name dnaUuidPropertyName = null;
- if (uuidProperty != null) {
- jcrUuidPropertyName = uuidProperty.getName();
- // Grab the first 'good' UUID value ...
- for (Object uuidValue : uuidProperty) {
- try {
- uuid = factories.getUuidFactory().create(uuidValue);
- break;
- } catch (ValueFormatException e) {
- // Ignore; just continue with the next property value
- }
- }
- }
- if (uuid == null) {
- // Look for the DNA UUID property ...
- org.jboss.dna.graph.property.Property dnaUuidProperty =
graphNode.getProperty(DnaLexicon.UUID);
- if (dnaUuidProperty != null) {
- dnaUuidPropertyName = dnaUuidProperty.getName();
- // Grab the first 'good' UUID value ...
- for (Object uuidValue : dnaUuidProperty) {
- try {
- uuid = factories.getUuidFactory().create(uuidValue);
- break;
- } catch (ValueFormatException e) {
- // Ignore; just continue with the next property value
- }
- }
- }
- }
-
// Now create the JCR property object wrapper around the "jcr:uuid"
property ...
Map<Name, Property> properties = new HashMap<Name, Property>();
- if (uuid == null) uuid = UUID.randomUUID();
if (referenceable) {
- if (uuidProperty == null) uuidProperty =
executionContext.getPropertyFactory().create(JcrLexicon.UUID, uuid);
PropertyDefinition propertyDefinition =
propertyDefinitionsByPropertyName.get(JcrLexicon.UUID);
properties.put(JcrLexicon.UUID, new JcrSingleValueProperty(node,
executionContext, propertyDefinition,
PropertyType.STRING, uuidProperty));
@@ -760,7 +839,7 @@
Name name = dnaProp.getName();
// Skip the JCR and DNA UUID properties (using the EXACT Name instances on
the Property) ...
- if (name == jcrUuidPropertyName || name == dnaUuidPropertyName) continue;
+ if (JcrLexicon.UUID.equals(name) || DnaLexicon.UUID.equals(name)) continue;
// Figure out the JCR property type for this property ...
PropertyDefinition propertyDefinition =
propertyDefinitionsByPropertyName.get(name);
@@ -826,10 +905,6 @@
}
}
- if (referenceable) {
- assert uuidProperty != null;
- }
-
// Now set the properties on the node ...
node.setProperties(properties);
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-03-05 18:20:33
UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-03-06 16:51:55
UTC (rev 761)
@@ -25,10 +25,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jcr.AccessDeniedException;
@@ -41,9 +37,6 @@
import javax.jcr.Workspace;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.observation.ObservationManager;
import javax.jcr.query.QueryManager;
@@ -111,14 +104,13 @@
/**
* Reference to the JCR type manager for this workspace.
*/
- private final NodeTypeManager nodeTypeManager;
+ private final JcrNodeTypeManager nodeTypeManager;
/**
* The {@link Session} instance that this corresponds with this workspace.
*/
private final JcrSession session;
- @SuppressWarnings( "synthetic-access" )
JcrWorkspace( JcrRepository repository,
String workspaceName,
ExecutionContext context,
@@ -156,26 +148,31 @@
this.session = new JcrSession(this.repository, this, this.context,
sessionAttributes);
// This must be initialized after the session
- this.nodeTypeManager = new JcrNodeTypeManager(new
DnaBuiltinNodeTypeSource(this.session,
+ this.nodeTypeManager = new JcrNodeTypeManager(this.session,
+ new
DnaBuiltinNodeTypeSource(this.session,
new
JcrBuiltinNodeTypeSource(this.session)));
}
- String getSourceName() {
+ final String getSourceName() {
return this.repository.getRepositorySourceName();
}
+ final JcrNodeTypeManager nodeTypeManager() {
+ return this.nodeTypeManager;
+ }
+
/**
* {@inheritDoc}
*/
- public String getName() {
+ public final String getName() {
return name;
}
/**
* {@inheritDoc}
*/
- public Session getSession() {
+ public final Session getSession() {
return this.session;
}
@@ -184,7 +181,7 @@
*
* @see javax.jcr.Workspace#getNamespaceRegistry()
*/
- public NamespaceRegistry getNamespaceRegistry() {
+ public final NamespaceRegistry getNamespaceRegistry() {
return workspaceRegistry;
}
@@ -203,21 +200,21 @@
/**
* {@inheritDoc}
*/
- public NodeTypeManager getNodeTypeManager() {
+ public final NodeTypeManager getNodeTypeManager() {
return nodeTypeManager;
}
/**
* {@inheritDoc}
*/
- public ObservationManager getObservationManager() {
+ public final ObservationManager getObservationManager() {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
- public QueryManager getQueryManager() {
+ public final QueryManager getQueryManager() {
throw new UnsupportedOperationException();
}
@@ -350,95 +347,4 @@
throw new UnsupportedOperationException();
}
- /**
- * Local implementation of @{link NodeTypeManager}. Initialized with {@link NodeType}
source data when it is created (in the
- * {@link JcrWorkspace} constructor.
- */
- @NotThreadSafe
- private class JcrNodeTypeManager implements NodeTypeManager {
-
- private final Map<Name, JcrNodeType> primaryNodeTypes;
- private final Map<Name, JcrNodeType> mixinNodeTypes;
-
- private JcrNodeTypeManager( JcrNodeTypeSource source ) {
- Collection<JcrNodeType> primary = source.getPrimaryNodeTypes();
- Collection<JcrNodeType> mixins = source.getMixinNodeTypes();
-
- primaryNodeTypes = new HashMap<Name, JcrNodeType>(primary.size());
- for (JcrNodeType nodeType : primary) {
- primaryNodeTypes.put(nodeType.getInternalName(), nodeType);
- }
-
- mixinNodeTypes = new HashMap<Name, JcrNodeType>(mixins.size());
- for (JcrNodeType nodeType : mixins) {
- mixinNodeTypes.put(nodeType.getInternalName(), nodeType);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.nodetype.NodeTypeManager#getAllNodeTypes()
- */
- public NodeTypeIterator getAllNodeTypes() {
-
- // TODO: Can revisit this approach later if it becomes a performance issue
- /*
- * Note also that this creates a subtle difference in behavior for concurrent
modification
- * between this method and the specific get*NodeTypes methods. That is, if a
type is added
- * while an iterator from the corresponding specific get*NodeType method is
being traversed,
- * a ConcurrentModificationException will be thrown. Because this iterator
is based on a copy
- * of the underlying maps, no exception would be thrown in the same case.
- */
-
- List<NodeType> allTypes = new
ArrayList<NodeType>(primaryNodeTypes.size() + mixinNodeTypes.size());
- allTypes.addAll(primaryNodeTypes.values());
- allTypes.addAll(mixinNodeTypes.values());
- return new JcrNodeTypeIterator(allTypes);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.nodetype.NodeTypeManager#getMixinNodeTypes()
- */
- public NodeTypeIterator getMixinNodeTypes() {
- return new JcrNodeTypeIterator(mixinNodeTypes.values());
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.nodetype.NodeTypeManager#getNodeType(java.lang.String)
- */
- @SuppressWarnings( "synthetic-access" )
- public NodeType getNodeType( String nodeTypeName ) throws
NoSuchNodeTypeException, RepositoryException {
- Name ntName =
session.getExecutionContext().getValueFactories().getNameFactory().create(nodeTypeName);
-
- NodeType nodeType = primaryNodeTypes.get(ntName);
-
- if (nodeType != null) {
- return nodeType;
- }
-
- nodeType = mixinNodeTypes.get(ntName);
-
- if (nodeType != null) {
- return nodeType;
- }
-
- throw new NoSuchNodeTypeException(JcrI18n.typeNotFound.text(nodeTypeName));
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.nodetype.NodeTypeManager#getPrimaryNodeTypes()
- */
- public NodeTypeIterator getPrimaryNodeTypes() {
- return new JcrNodeTypeIterator(primaryNodeTypes.values());
- }
-
- }
-
}
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-03-05
18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-03-06
16:51:55 UTC (rev 761)
@@ -53,6 +53,7 @@
invalidNamePattern = The "{1}" name pattern contained the '{0}'
character, which is not allowed in a name pattern
itemNotFoundWithUuid = An item with UUID "{0}" could not be found in workspace
"{1}"
errorWhileFindingNodeWithUuid = Error while finding the item with UUID "{0}" in
workspace "{1}"
+nodeDefinitionCouldBeDeterminedForNode = Unable to determine a valid node definition for
the node "{0}" in workspace "{1}"
REP_NAME_DESC = DNA Repository
REP_VENDOR_DESC = JBoss - A division of Red Hat Middleware LLC
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-03-05
18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-03-06
16:51:55 UTC (rev 761)
@@ -26,6 +26,7 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
import java.io.InputStream;
import java.util.ArrayList;
@@ -46,6 +47,7 @@
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.version.Version;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
@@ -83,7 +85,7 @@
MockAbstractJcrNode( JcrSession session,
String name,
Node parent ) {
- super(session);
+ super(session, mock(NodeDefinition.class));
this.name = name;
this.parent = parent;
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java 2009-03-05 18:20:33 UTC
(rev 760)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java 2009-03-06 16:51:55 UTC
(rev 761)
@@ -33,6 +33,7 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.Property;
+import javax.jcr.nodetype.NodeDefinition;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
@@ -52,18 +53,22 @@
private Node root;
@Mock
private JcrSession session;
+ @Mock
+ private NodeDefinition rootNodeDefinition;
+ @Mock
+ private NodeDefinition nodeDefinition;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
- root = new JcrRootNode(session);
+ root = new JcrRootNode(session, rootNodeDefinition);
Segment segment = Mockito.mock(Segment.class);
Name name = Mockito.mock(Name.class);
stub(name.getString((NamespaceRegistry)anyObject())).toReturn("name");
stub(segment.getName()).toReturn(name);
stub(segment.getIndex()).toReturn(2);
UUID uuid = UUID.randomUUID();
- node = new JcrNode(session, uuid, segment);
+ node = new JcrNode(session, uuid, segment, nodeDefinition);
ExecutionContext context = Mockito.mock(ExecutionContext.class);
stub(session.getExecutionContext()).toReturn(context);
stub(session.getNode(uuid)).toReturn(root);
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java 2009-03-05 18:20:33
UTC (rev 760)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java 2009-03-06 16:51:55
UTC (rev 761)
@@ -30,6 +30,7 @@
import java.util.Map;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Property;
+import javax.jcr.nodetype.NodeDefinition;
import org.jboss.dna.graph.property.Name;
import org.junit.Before;
import org.junit.Test;
@@ -44,13 +45,15 @@
private JcrRootNode root;
@Mock
private JcrSession session;
+ @Mock
+ private NodeDefinition nodeDefinition;
private Map<Name, Property> properties;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
properties = new HashMap<Name, Property>();
- root = new JcrRootNode(session);
+ root = new JcrRootNode(session, nodeDefinition);
root.setProperties(properties);
}