Author: rhauch
Date: 2009-03-16 18:50:09 -0400 (Mon, 16 Mar 2009)
New Revision: 777
Added:
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/PropertyId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyNodeIteratorTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyPropertyIteratorTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
trunk/dna-jcr/src/test/resources/vehicles.xml
Removed:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeIteratorTest.java
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrItem.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNodeTypeSource.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaBuiltinNodeTypeSource.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.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/JcrNodeTypeManager.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.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/JcrSingleValueProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSystemViewExporter.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/AbstractJcrItemTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java
trunk/dna-jcr/src/test/resources/cars.xml
Log:
DNA-194 Implement update JCR capability
Applied the patch file (just recently attached to the issue) that captures the refactoring
to pull the management of the session's cached and updated state out of the individual
Node and Property implementations and into a new "SessionCache" class.
This class does a couple of different things. First, it centralizes all of the information
about the nodes and properties that have been loaded from the repository source, making it
easier to track the cached information as well as track/manage the changes made within the
session. Remember that some activities, such as "refresh" or "save"
can be performed on one node but could potentially affect many other objects. By
centralizing all the cached and transient state, it's much easier to manage all this
information. It also makes it much easier to alter the data structure used to manage the
cache (for example to make it thread-safe), should that be required at a later time.
Second, it manages the Node and Property implementation objects (which can be held onto by
clients), ensuring that the same Node and Property instances are always returned for the
same logical instance. These instances are managed by ReferenceMaps, allowing the garbage
collector to remove entries when clients no longer hold onto the Node and Property objects
(with normal references). The implementation classes of Node and Property (e.g.,
AbstractJcrNode and its concrete subclasses, and AbstractJcrProperty and its concrete
subclasses) no longer directly hold onto the detailed node and property information being
cached in SessionCache, but rather hold identifiers and dynamically look up the
information when necessary. This ensures that a particular Node implementation object
obtained for a node will always present the most up-to-date information about the node,
even if that information is changed by the session or other objects.
(Note that it would be very easy for each Node and Property implementation to locally
cache the reference to the SessionCache's node information and/or property
information, saving some repeated lookups using the SessionCache's methods, but since
the SessionCache knows about the implementations it could invalidate these local
references when needed. This could be done at a later time when we've proven that the
current simple approach needs to be improved.)
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrItem.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrItem.java 2009-03-12 20:54:55
UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrItem.java 2009-03-16 22:50:09
UTC (rev 777)
@@ -26,26 +26,62 @@
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
/**
* @author jverhaeg
*/
abstract class AbstractJcrItem implements Item {
- protected final String getPath( String absolutePath,
- String relativePath ) {
- assert absolutePath != null;
- assert absolutePath.length() > 0;
- assert relativePath != null;
- if (absolutePath.charAt(absolutePath.length() - 1) == '/') {
- return absolutePath + relativePath;
- }
- return absolutePath + '/' + relativePath;
+ protected final SessionCache cache;
+
+ protected AbstractJcrItem( SessionCache cache ) {
+ assert cache != null;
+ this.cache = cache;
}
/**
* {@inheritDoc}
*
+ * @see javax.jcr.Item#getSession()
+ */
+ public Session getSession() {
+ return cache.session();
+ }
+
+ final JcrSession session() {
+ return cache.session();
+ }
+
+ final ExecutionContext context() {
+ return cache.context();
+ }
+
+ final Name nameFrom( String name ) {
+ return context().getValueFactories().getNameFactory().create(name);
+ }
+
+ final Path pathFrom( String path ) {
+ return context().getValueFactories().getPathFactory().create(path);
+ }
+
+ final Path.Segment segmentFrom( String segment ) {
+ return context().getValueFactories().getPathFactory().createSegment(segment);
+ }
+
+ final NamespaceRegistry namespaces() {
+ return context().getNamespaceRegistry();
+ }
+
+ abstract Path path() throws RepositoryException;
+
+ /**
+ * {@inheritDoc}
+ *
* @return <code>false</code>
* @see javax.jcr.Item#isModified()
*/
@@ -96,7 +132,7 @@
*
* @see javax.jcr.Item#getAncestor(int)
*/
- public final Item getAncestor( int depth ) throws RepositoryException {
+ public Item getAncestor( int depth ) throws RepositoryException {
if (depth < 0) {
throw new ItemNotFoundException(JcrI18n.noNegativeDepth.text(depth));
}
@@ -127,7 +163,7 @@
* @see javax.jcr.Item#getDepth()
*/
public int getDepth() throws RepositoryException {
- return getParent().getDepth() + 1;
+ return path().size();
}
/**
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-12 20:54:55
UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-03-16 22:50:09
UTC (rev 777)
@@ -25,11 +25,10 @@
import java.io.InputStream;
import java.util.Calendar;
-import java.util.HashSet;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.jcr.Item;
@@ -42,7 +41,6 @@
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
-import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.lock.Lock;
@@ -51,93 +49,51 @@
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
-import net.jcip.annotations.NotThreadSafe;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.Location;
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.ValueFormatException;
+import org.jboss.dna.jcr.SessionCache.ChildNode;
+import org.jboss.dna.jcr.SessionCache.Children;
+import org.jboss.dna.jcr.SessionCache.NodeInfo;
/**
- * @author jverhaeg
+ * An abstract implementation of the JCR {@link Node} interface. Instances of this class
are created and managed by the
+ * {@link SessionCache}. Each instance references the {@link SessionCache.NodeInfo node
information} also managed by the
+ * SessionCache, and finds and operates against this information with each method call.
*/
-@NotThreadSafe
+@Immutable
abstract class AbstractJcrNode extends AbstractJcrItem implements Node {
private static final NodeType[] EMPTY_NODE_TYPES = new NodeType[] {};
- private final JcrSession session;
- private final NodeDefinition definition;
- protected Location location;
- private Map<Name, Property> properties;
- private List<Location> children;
+ protected final UUID nodeUuid;
- AbstractJcrNode( JcrSession session,
- Location location,
- NodeDefinition definition ) {
- assert session != null;
- assert definition != null;
- assert location != null;
- this.location = location;
- this.session = session;
- this.definition = definition;
+ AbstractJcrNode( SessionCache cache,
+ UUID nodeUuid ) {
+ super(cache);
+ this.nodeUuid = nodeUuid;
}
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Item#getSession()
- */
- public Session getSession() {
- return session;
- }
+ abstract boolean isRoot();
- final JcrSession session() {
- return session;
- }
-
final UUID internalUuid() {
- return location.getUuid();
+ return nodeUuid;
}
- /**
- * Change the internal UUID. Technically, it is possible for this to change, but only
because a new node may be assigned a
- * UUID when it is created within the session and (according to the spec) this UUID
can change when the new node is persisted
- * upon {@link #save()}.
- *
- * @param uuid the new UUID; may not be null
- */
- final void setInternalUuid( UUID uuid ) {
- assert uuid != null;
- location = location.with(uuid);
+ final NodeInfo nodeInfo() throws ItemNotFoundException, RepositoryException {
+ return cache.findNodeInfo(nodeUuid);
}
- final void setChildren( List<Location> children ) {
- assert children != null;
- this.children = children;
+ @Override
+ Path path() throws RepositoryException {
+ return cache.getPathFor(nodeInfo());
}
- final void setProperties( Map<Name, Property> properties ) {
- assert properties != null;
- 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()
@@ -148,7 +104,7 @@
if (mixinsProp != null) {
String referenceableMixinName =
JcrMixLexicon.REFERENCEABLE.getString(namespaces());
for (Value value : mixinsProp.getValues()) {
- if (referenceableMixinName.equals(value.getString())) return
getProperty(JcrLexicon.UUID).getString();
+ if (referenceableMixinName.equals(value.getString())) return
nodeUuid.toString();
}
}
throw new UnsupportedRepositoryOperationException();
@@ -192,8 +148,9 @@
*
* @see javax.jcr.Node#getDefinition()
*/
- public NodeDefinition getDefinition() {
- return definition;
+ public NodeDefinition getDefinition() throws RepositoryException {
+ NodeDefinitionId definitionId = nodeInfo().getDefinitionId();
+ return session().nodeTypeManager().getNodeDefinition(definitionId);
}
/**
@@ -203,8 +160,8 @@
* @see javax.jcr.Node#getPrimaryNodeType()
*/
public NodeType getPrimaryNodeType() throws RepositoryException {
- String nodeTypeName = getProperty(JcrLexicon.PRIMARY_TYPE).getString();
- return session.getWorkspace().getNodeTypeManager().getNodeType(nodeTypeName);
+ Name primaryTypeName = nodeInfo().getPrimaryTypeName();
+ return session().nodeTypeManager().getNodeType(primaryTypeName);
}
/**
@@ -214,7 +171,7 @@
* @see javax.jcr.Node#getMixinNodeTypes()
*/
public NodeType[] getMixinNodeTypes() throws RepositoryException {
- NodeTypeManager nodeTypeManager = session.getWorkspace().getNodeTypeManager();
+ NodeTypeManager nodeTypeManager = session().getWorkspace().getNodeTypeManager();
Property mixinTypesProperty = getProperty(JcrLexicon.MIXIN_TYPES);
if (mixinTypesProperty == null) return EMPTY_NODE_TYPES;
List<NodeType> mixinNodeTypes = new LinkedList<NodeType>();
@@ -252,12 +209,35 @@
* @see javax.jcr.Node#getPrimaryItem()
*/
public final Item getPrimaryItem() throws RepositoryException {
- // TODO: Check if declared in the node type first
+ // Get the primary item name from this node's type ...
+ NodeType primaryType = getPrimaryNodeType();
+ String primaryItemNameString = primaryType.getPrimaryItemName();
+ if (primaryItemNameString == null) {
+ I18n msg = JcrI18n.noPrimaryItemNameDefinedOnPrimaryType;
+ throw new ItemNotFoundException(msg.text(primaryType.getName(), getPath(),
cache.workspaceName()));
+ }
try {
- Property primaryItemProp = getProperty("jcr:primaryItemName");
- return session.getItem(getPath(getPath(), primaryItemProp.getString()));
+ Path primaryItemPath =
context().getValueFactories().getPathFactory().create(primaryItemNameString);
+ if (primaryItemPath.size() != 1 || primaryItemPath.isAbsolute()) {
+ I18n msg = JcrI18n.primaryItemNameForPrimaryTypeIsNotValid;
+ throw new ItemNotFoundException(msg.text(primaryType.getName(),
+ primaryItemNameString,
+ getPath(),
+ cache.workspaceName()));
+ }
+ return cache.findJcrItem(nodeUuid, primaryItemPath);
+ } catch (ValueFormatException error) {
+ I18n msg = JcrI18n.primaryItemNameForPrimaryTypeIsNotValid;
+ throw new ItemNotFoundException(msg.text(primaryType.getName(),
+ primaryItemNameString,
+ getPath(),
+ cache.workspaceName()));
} catch (PathNotFoundException error) {
- throw new ItemNotFoundException(error);
+ I18n msg = JcrI18n.primaryItemDoesNotExist;
+ throw new ItemNotFoundException(msg.text(primaryType.getName(),
+ primaryItemNameString,
+ getPath(),
+ cache.workspaceName()));
}
}
@@ -268,7 +248,7 @@
* @see javax.jcr.Item#isSame(javax.jcr.Item)
*/
@Override
- public final boolean isSame( Item otherItem ) throws RepositoryException {
+ public boolean isSame( Item otherItem ) throws RepositoryException {
CheckArg.isNotNull(otherItem, "otherItem");
if (super.isSame(otherItem) && otherItem instanceof Node) {
if (otherItem instanceof AbstractJcrNode) {
@@ -285,9 +265,8 @@
*
* @see javax.jcr.Node#hasProperties()
*/
- public final boolean hasProperties() {
- assert properties != null;
- return !properties.isEmpty();
+ public final boolean hasProperties() throws RepositoryException {
+ return nodeInfo().getProperties().size() > 0;
}
/**
@@ -299,10 +278,17 @@
public final boolean hasProperty( String relativePath ) throws RepositoryException {
CheckArg.isNotEmpty(relativePath, "relativePath");
if (relativePath.indexOf('/') >= 0) {
- return (getProperty(relativePath) != null);
+ try {
+ getProperty(relativePath);
+ return true;
+ } catch (PathNotFoundException e) {
+ return false;
+ }
}
- assert properties != null;
- return properties.containsKey(nameFrom(relativePath));
+ if (relativePath.equals(".")) return false;
+ if (relativePath.equals("..")) return false;
+ // Otherwise it should be a property on this node ...
+ return cache.findPropertyInfo(new PropertyId(nodeUuid, nameFrom(relativePath)))
!= null;
}
/**
@@ -310,8 +296,8 @@
*
* @see javax.jcr.Node#getProperties()
*/
- public final PropertyIterator getProperties() {
- return new JcrPropertyIterator(properties.values());
+ public final PropertyIterator getProperties() throws RepositoryException {
+ return new JcrPropertyIterator(cache.findJcrPropertiesFor(nodeUuid));
}
/**
@@ -323,40 +309,67 @@
CheckArg.isNotNull(namePattern, "namePattern");
namePattern = namePattern.trim();
if (namePattern.length() == 0) return new JcrEmptyPropertyIterator();
- if ("*".equals(namePattern)) return new
JcrPropertyIterator(properties.values());
+ Collection<AbstractJcrProperty> properties =
cache.findJcrPropertiesFor(nodeUuid);
+ if ("*".equals(namePattern)) return new
JcrPropertyIterator(properties);
+
+ // Figure out the patterns for each of the different disjunctions in the supplied
pattern ...
List<Object> patterns = createPatternsFor(namePattern);
- // Implementing exact-matching only for now to prototype types as properties
- Set<Property> matchingProps = new HashSet<Property>();
- boolean foundMatch = false;
- for (Property property : properties.values()) {
+ // Go through the properties and remove any property that doesn't match a
pattern ...
+ boolean foundMatch = true;
+ Collection<AbstractJcrProperty> matchingProperties = new
LinkedList<AbstractJcrProperty>();
+ Iterator<AbstractJcrProperty> iter = properties.iterator();
+ while (iter.hasNext()) {
+ AbstractJcrProperty property = iter.next();
String propName = property.getName();
+ assert foundMatch == true;
for (Object patternOrMatch : patterns) {
if (patternOrMatch instanceof Pattern) {
Pattern pattern = (Pattern)patternOrMatch;
- if (pattern.matcher(propName).matches()) foundMatch = true;
+ if (pattern.matcher(propName).matches()) break;
} else {
String match = (String)patternOrMatch;
- if (propName.equals(match)) foundMatch = true;
+ if (propName.equals(match)) break;
}
- if (foundMatch) {
- foundMatch = false;
- matchingProps.add(property);
- break;
- }
+ // No pattern matched ...
+ foundMatch = false;
}
+ if (foundMatch) {
+ matchingProperties.add(property);
+ foundMatch = true; // for the next iteration ..
+ }
}
- return new JcrPropertyIterator(matchingProps);
+ return new JcrPropertyIterator(matchingProperties);
}
/**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException always
+ * @see javax.jcr.Node#getReferences()
+ */
+ public final PropertyIterator getReferences() throws RepositoryException {
+ // Iterate through the properties to see which ones have a REFERENCE type ...
+ Collection<AbstractJcrProperty> properties =
cache.findJcrPropertiesFor(nodeUuid);
+ Collection<AbstractJcrProperty> references = new
LinkedList<AbstractJcrProperty>();
+ Iterator<AbstractJcrProperty> iter = properties.iterator();
+ while (iter.hasNext()) {
+ AbstractJcrProperty property = iter.next();
+ if (property.getType() == PropertyType.REFERENCE) references.add(property);
+ }
+ if (references.isEmpty()) return new JcrEmptyPropertyIterator();
+ return new JcrPropertyIterator(references);
+ }
+
+ /**
* A non-standard method to obtain a property given the {@link Name DNA Name} object.
This method is faster
*
* @param propertyName the property name
* @return the JCR property with the supplied name, or null if the property
doesn't exist
+ * @throws RepositoryException if there is an error finding the property with the
supplied name
*/
- public final Property getProperty( Name propertyName ) {
- return properties.get(propertyName);
+ public final Property getProperty( Name propertyName ) throws RepositoryException {
+ return cache.findJcrProperty(new PropertyId(nodeUuid, propertyName));
}
/**
@@ -367,19 +380,23 @@
*/
public final Property getProperty( String relativePath ) throws RepositoryException
{
CheckArg.isNotEmpty(relativePath, "relativePath");
- if (relativePath.indexOf('/') >= 0) {
- Item item = session.getItem(getPath(getPath(), relativePath));
+ int indexOfFirstSlash = relativePath.indexOf('/');
+ if (indexOfFirstSlash == 0) {
+ // Not a relative path ...
+ throw new
IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath));
+ }
+ if (indexOfFirstSlash != -1) {
+ // We know it's a relative path with more than one segment ...
+ Path path = pathFrom(relativePath).getNormalizedPath();
+ AbstractJcrItem item = cache.findJcrItem(nodeUuid, path);
if (item instanceof Property) {
return (Property)item;
}
- // The item must be a node.
- assert item instanceof Node;
- // Since session.getItem() gives precedence to nodes over properties, try
explicitly looking for the property with the
- // same name as the found node using the returned node's parent.
- return ((Node)item).getParent().getProperty(item.getName());
+ I18n msg = JcrI18n.propertyNotFoundAtPathRelativeToReferenceNode;
+ throw new PathNotFoundException(msg.text(relativePath, getPath(),
cache.workspaceName()));
}
- assert properties != null;
- Property property = properties.get(nameFrom(relativePath));
+ // It's just a name, so look for it directly ...
+ Property property = getProperty(nameFrom(relativePath));
if (property != null) return property;
throw new PathNotFoundException();
}
@@ -387,45 +404,31 @@
/**
* {@inheritDoc}
*
- * @throws UnsupportedOperationException always
- * @see javax.jcr.Node#getReferences()
- */
- public final PropertyIterator getReferences() throws RepositoryException {
- // Iterate through the properties to see which ones have a REFERENCE type ...
- Set<Property> references = new HashSet<Property>();
- for (Property property : properties.values()) {
- if (property.getType() == PropertyType.REFERENCE) references.add(property);
- }
- if (references.isEmpty()) return new JcrEmptyPropertyIterator();
- return new JcrPropertyIterator(references);
- }
-
- /**
- * {@inheritDoc}
- *
* @throws IllegalArgumentException if <code>relativePath</code> is empty
or <code>null</code>.
* @see javax.jcr.Node#hasNode(java.lang.String)
*/
public final boolean hasNode( String relativePath ) throws RepositoryException {
CheckArg.isNotEmpty(relativePath, "relativePath");
- if (relativePath.indexOf('/') >= 0) {
- return (getNode(relativePath) != null);
+ if (relativePath.equals(".")) return true;
+ if (relativePath.equals("..")) return isRoot() ? false : true;
+ int indexOfFirstSlash = relativePath.indexOf('/');
+ if (indexOfFirstSlash == 0) {
+ // Not a relative path ...
+ throw new
IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath));
}
- if (children != null) {
+ if (indexOfFirstSlash != -1) {
+ Path path = pathFrom(relativePath).getNormalizedPath();
try {
- Path.Segment segment = session.getExecutionContext()
- .getValueFactories()
- .getPathFactory()
- .createSegment(relativePath);
- for (Location child : children) {
- Path.Segment childSegment = child.getPath().getLastSegment();
- if (childSegment.equals(segment)) return true;
- }
- } catch (ValueFormatException e) {
- throw new
RepositoryException(JcrI18n.invalidRelativePath.text(relativePath));
+ AbstractJcrNode item = cache.findJcrNode(nodeUuid, path);
+ return item != null;
+ } catch (PathNotFoundException e) {
+ return false;
}
}
- return false;
+ // It's just a name, so look for a child ...
+ Path.Segment segment = segmentFrom(relativePath);
+ ChildNode child = nodeInfo().getChildren().getChild(segment);
+ return child != null;
}
/**
@@ -433,8 +436,8 @@
*
* @see javax.jcr.Node#hasNodes()
*/
- public final boolean hasNodes() {
- return (children != null && !children.isEmpty());
+ public final boolean hasNodes() throws RepositoryException {
+ return nodeInfo().getChildren().size() > 0;
}
/**
@@ -445,12 +448,31 @@
*/
public final Node getNode( String relativePath ) throws RepositoryException {
CheckArg.isNotEmpty(relativePath, "relativePath");
- String path = getPath(getPath(), relativePath);
- Item item = getSession().getItem(path);
- if (item instanceof Node) {
- return (Node)item;
+ if (relativePath.equals(".")) return this;
+ if (relativePath.equals("..")) return this.getParent();
+ int indexOfFirstSlash = relativePath.indexOf('/');
+ if (indexOfFirstSlash == 0) {
+ // Not a relative path ...
+ throw new
IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath));
}
- throw new PathNotFoundException();
+ if (indexOfFirstSlash != -1) {
+ // We know it's a relative path with more than one segment ...
+ Path path = pathFrom(relativePath).getNormalizedPath();
+ AbstractJcrItem item = cache.findJcrItem(nodeUuid, path);
+ if (item instanceof Node) {
+ return (Node)item;
+ }
+ I18n msg = JcrI18n.nodeNotFoundAtPathRelativeToReferenceNode;
+ throw new PathNotFoundException(msg.text(relativePath, getPath(),
cache.workspaceName()));
+ }
+ // It's just a name, so look for a child ...
+ Path.Segment segment = segmentFrom(relativePath);
+ ChildNode child = nodeInfo().getChildren().getChild(segment);
+ if (child != null) {
+ return cache.findJcrNode(child.getUuid());
+ }
+ String msg = JcrI18n.childNotFoundUnderNode.text(segment, getPath(),
cache.workspaceName());
+ throw new PathNotFoundException(msg);
}
/**
@@ -458,11 +480,12 @@
*
* @see javax.jcr.Node#getNodes()
*/
- public final NodeIterator getNodes() {
- if (children == null) {
+ public final NodeIterator getNodes() throws RepositoryException {
+ Children children = nodeInfo().getChildren();
+ if (children.size() == 0) {
return new JcrEmptyNodeIterator();
}
- return new JcrChildNodeIterator(this, children);
+ return new JcrChildNodeIterator(cache, children, children.size());
}
/**
@@ -479,11 +502,12 @@
List<Object> patterns = createPatternsFor(namePattern);
// Implementing exact-matching only for now to prototype types as properties
- List<Location> matchingChildren = new LinkedList<Location>();
+ Children children = nodeInfo().getChildren();
+ List<ChildNode> matchingChildren = new LinkedList<ChildNode>();
NamespaceRegistry registry = namespaces();
boolean foundMatch = false;
- for (Location child : children) {
- String childName =
child.getPath().getLastSegment().getName().getString(registry);
+ for (ChildNode child : children) {
+ String childName = child.getName().getString(registry);
for (Object patternOrMatch : patterns) {
if (patternOrMatch instanceof Pattern) {
Pattern pattern = (Pattern)patternOrMatch;
@@ -499,7 +523,7 @@
}
}
}
- return new JcrChildNodeIterator(this, matchingChildren);
+ return new JcrChildNodeIterator(cache, matchingChildren,
matchingChildren.size());
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNodeTypeSource.java
===================================================================
---
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNodeTypeSource.java 2009-03-12
20:54:55 UTC (rev 776)
+++
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNodeTypeSource.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -44,9 +44,9 @@
protected static final List<JcrNodeDefinition> NO_CHILD_NODES =
Collections.<JcrNodeDefinition>emptyList();
protected static final List<JcrPropertyDefinition> NO_PROPERTIES =
Collections.<JcrPropertyDefinition>emptyList();
- // Indicates that the node type has no primary item name - added for readability
+ /** Indicates that the node type has no primary item name - added for readability */
protected static final Name NO_PRIMARY_ITEM_NAME = null;
- // Indicates that the definition should apply to all property definition or child
node definitions - added for readability
+ /** Indicates that the definition should apply to all property definition or child
node definitions - added for readability */
protected static final Name ALL_NODES = null;
// Indicates whether or not the node type is a mixin - added for readability
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -28,14 +28,16 @@
import javax.jcr.Item;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
-import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.nodetype.PropertyDefinition;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.jcr.SessionCache.PropertyInfo;
/**
* @author jverhaeg
@@ -43,22 +45,13 @@
@NotThreadSafe
abstract class AbstractJcrProperty extends AbstractJcrItem implements Property {
- private final AbstractJcrNode node;
- private final org.jboss.dna.graph.property.Property dnaProperty;
- private final PropertyDefinition jcrPropertyDefinition;
- private final int propertyType;
+ private final PropertyId propertyId;
- AbstractJcrProperty( AbstractJcrNode node,
- PropertyDefinition definition,
- int propertyType,
- org.jboss.dna.graph.property.Property dnaProperty ) {
- assert node != null;
- assert dnaProperty != null;
- assert definition != null;
- this.node = node;
- this.dnaProperty = dnaProperty;
- this.jcrPropertyDefinition = definition;
- this.propertyType = propertyType;
+ AbstractJcrProperty( SessionCache cache,
+ PropertyId propertyId ) {
+ super(cache);
+ assert propertyId != null;
+ this.propertyId = propertyId;
}
/**
@@ -72,25 +65,34 @@
visitor.visit(this);
}
- JcrValue createValue( Object value ) {
- return new JcrValue(getExecutionContext().getValueFactories(), getType(),
value);
+ final PropertyInfo propertyInfo() throws PathNotFoundException, RepositoryException
{
+ return cache.findPropertyInfo(propertyId);
}
- final ExecutionContext getExecutionContext() {
- return node.session().getExecutionContext();
+ final Name name() throws RepositoryException {
+ return propertyInfo().getPropertyName();
}
- final org.jboss.dna.graph.property.Property getDnaProperty() {
- return dnaProperty;
+ final org.jboss.dna.graph.property.Property property() throws RepositoryException {
+ return propertyInfo().getProperty();
}
+ JcrValue createValue( Object value ) throws RepositoryException {
+ return new JcrValue(context().getValueFactories(),
propertyInfo().getPropertyType(), value);
+ }
+
+ @Override
+ Path path() throws RepositoryException {
+ return cache.getPathFor(propertyInfo());
+ }
+
/**
* {@inheritDoc}
*
* @see javax.jcr.Property#getType()
*/
- public final int getType() {
- return propertyType;
+ public int getType() throws RepositoryException {
+ return propertyInfo().getPropertyType();
}
/**
@@ -98,8 +100,11 @@
*
* @see javax.jcr.Property#getDefinition()
*/
- public final PropertyDefinition getDefinition() {
- return jcrPropertyDefinition;
+ public final PropertyDefinition getDefinition() throws RepositoryException {
+ PropertyInfo info = propertyInfo();
+ PropertyDefinitionId definitionId = info.getDefinitionId();
+ boolean multiValued = info.isMultiValued();
+ return cache.session().nodeTypeManager().getPropertyDefinition(definitionId,
multiValued);
}
/**
@@ -111,8 +116,8 @@
*
* @see javax.jcr.Item#getName()
*/
- public final String getName() {
- return dnaProperty.getName().getString(node.namespaces());
+ public final String getName() throws RepositoryException {
+ return propertyInfo().getPropertyName().getString(namespaces());
}
/**
@@ -120,8 +125,8 @@
*
* @see javax.jcr.Item#getParent()
*/
- public final Node getParent() {
- return node;
+ public final Node getParent() throws RepositoryException {
+ return cache.findJcrNode(propertyId.getNodeId());
}
/**
@@ -130,21 +135,12 @@
* @see javax.jcr.Item#getPath()
*/
public final String getPath() throws RepositoryException {
- return getPath(node.getPath(), getName());
+ return cache.getPathFor(propertyInfo()).getString(namespaces());
}
/**
* {@inheritDoc}
*
- * @see javax.jcr.Item#getSession()
- */
- public final Session getSession() {
- return node.getSession();
- }
-
- /**
- * {@inheritDoc}
- *
* @return false
* @see javax.jcr.Item#isNode()
*/
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaBuiltinNodeTypeSource.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaBuiltinNodeTypeSource.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaBuiltinNodeTypeSource.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -127,18 +127,25 @@
NO_PRIMARY_ITEM_NAME, Arrays.asList(new
JcrNodeDefinition[] {
new JcrNodeDefinition(session, null,
JcrLexicon.SYSTEM,
OnParentVersionBehavior.IGNORE.getJcrValue(), true, true,
- true, false,
DnaLexicon.NAMESPACES,
- new NodeType[]
{namespaces}),
- new JcrNodeDefinition(session, null,
null,
+ true, false,
DnaLexicon.SYSTEM, new NodeType[] {system}),
+ new JcrNodeDefinition(session, null,
ALL_NODES,
OnParentVersionBehavior.VERSION.getJcrValue(), false, false,
- false, true,
DnaLexicon.NAMESPACES,
- new NodeType[]
{namespaces}),
+ false, true,
JcrNtLexicon.UNSTRUCTURED,
+ new NodeType[]
{base}),
- }), NO_PROPERTIES, NOT_MIXIN,
UNORDERABLE_CHILD_NODES);
+ }), Arrays.asList(new JcrPropertyDefinition[]
{
+ new JcrPropertyDefinition(session, null,
ALL_NODES,
+
OnParentVersionBehavior.COPY.getJcrValue(), false,
+ false, false,
NO_DEFAULT_VALUES, PropertyType.UNDEFINED,
+ NO_CONSTRAINTS,
false),
+ new JcrPropertyDefinition(session, null,
ALL_NODES,
+
OnParentVersionBehavior.COPY.getJcrValue(), false,
+ false, false,
NO_DEFAULT_VALUES, PropertyType.UNDEFINED,
+ NO_CONSTRAINTS,
true),}), NOT_MIXIN,
+ ORDERABLE_CHILD_NODES);
-
- primaryNodeTypes.addAll(Arrays.asList(new JcrNodeType[] {root, system,
namespaces, namespace, }));
- mixinNodeTypes.addAll(Arrays.asList(new JcrNodeType[] { }));
+ primaryNodeTypes.addAll(Arrays.asList(new JcrNodeType[] {root, system,
namespaces, namespace,}));
+ mixinNodeTypes.addAll(Arrays.asList(new JcrNodeType[] {}));
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -24,34 +24,31 @@
package org.jboss.dna.jcr;
import java.util.Iterator;
-import java.util.List;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.Location;
+import org.jboss.dna.jcr.SessionCache.ChildNode;
/**
- * @author jverhaeg
*/
@Immutable
final class JcrChildNodeIterator implements NodeIterator {
- private final AbstractJcrNode parent;
- private final Iterator<Location> iterator;
- private final JcrSession session;
+ private final SessionCache cache;
+ private final Iterator<ChildNode> iterator;
private int ndx;
private int size;
- JcrChildNodeIterator( AbstractJcrNode parent,
- List<Location> children ) {
- assert parent != null;
+ JcrChildNodeIterator( SessionCache cache,
+ Iterable<ChildNode> children,
+ int size ) {
+ assert cache != null;
assert children != null;
- this.parent = parent;
- this.session = parent.session();
+ this.cache = cache;
iterator = children.iterator();
- size = children.size();
+ this.size = size;
}
/**
@@ -96,10 +93,10 @@
* @see javax.jcr.NodeIterator#nextNode()
*/
public Node nextNode() {
- Location location = iterator.next();
+ ChildNode child = iterator.next();
ndx++;
try {
- return session.getChild(parent, location);
+ return cache.findJcrNode(child.getUuid());
} catch (RepositoryException error) {
throw new RuntimeException(error);
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -57,7 +57,7 @@
class JcrDocumentViewExporter extends AbstractJcrExporter {
private static final TextEncoder VALUE_ENCODER = new
JcrDocumentViewExporter.JcrDocumentViewPropertyEncoder();
-
+
JcrDocumentViewExporter( JcrSession session ) {
super(session, Collections.<String>emptyList());
}
@@ -103,7 +103,7 @@
continue;
}
- Name propName = ((AbstractJcrProperty)prop).getDnaProperty().getName();
+ Name propName = ((AbstractJcrProperty)prop).name();
String localPropName = getPrefixedName(propName);
@@ -141,16 +141,15 @@
}
endElement(contentHandler, name);
-
+
}
/**
- * Indicates whether the current node is an XML text node as per section 6.4.2.3 of
the JCR 1.0 specification.
- * XML text nodes are nodes that have the name "jcr:xmltext" and
only one property (besides the mandatory
- * "jcr:primaryType"). The property must have a property name of
"jcr:xmlcharacters", a type of <code>String</code>,
- * and does not have multiple values.<p/>
- * In practice, this is handled in DNA by making XML text nodes have a type of
"dna:xmltext", which
- * enforces these property characteristics.
+ * Indicates whether the current node is an XML text node as per section 6.4.2.3 of
the JCR 1.0 specification. XML text nodes
+ * are nodes that have the name "jcr:xmltext" and only one property
(besides the mandatory
+ * "jcr:primaryType"). The property must have a property name of
"jcr:xmlcharacters", a type of
+ * <code>String</code>, and does not have multiple values.<p/> In
practice, this is handled in DNA by making XML text nodes
+ * have a type of "dna:xmltext", which enforces these property
characteristics.
*
* @param node the node to test
* @return whether this node is a special xml text node
@@ -190,8 +189,8 @@
}
/**
- * Returns the XML characters for the given node.
- * The node must be an XML text node, as defined in {@link #isXmlTextNode(Node)}.
+ * Returns the XML characters for the given node. The node must be an XML text node,
as defined in
+ * {@link #isXmlTextNode(Node)}.
*
* @param node the node for which XML characters will be retrieved.
* @return the xml characters for this node
@@ -201,7 +200,7 @@
// ./xmltext/xmlcharacters exception (see JSR-170 Spec 6.4.2.3)
assert isXmlTextNode(node);
-
+
Property xmlCharacters =
node.getProperty(getPrefixedName(JcrLexicon.XMLCHARACTERS));
assert xmlCharacters != null;
@@ -221,22 +220,21 @@
/**
* Special {@link TextEncoder} that implements the subset of XML name encoding
suggested by section 6.4.4 of the JCR 1.0.1
- * specification. This encoder only encodes space (0x20), carriage return (0x0D),
new line (0x0A), tab (0x09), and any
+ * specification. This encoder only encodes space (0x20), carriage return (0x0D), new
line (0x0A), tab (0x09), and any
* underscore characters that might otherwise suggest an encoding, as defined in
{@link XmlNameEncoder}.
- *
*/
protected static class JcrDocumentViewPropertyEncoder extends XmlNameEncoder {
private static final Set<Character> MAPPED_CHARACTERS;
-
+
static {
MAPPED_CHARACTERS = new HashSet<Character>();
MAPPED_CHARACTERS.add(' ');
MAPPED_CHARACTERS.add('\r');
MAPPED_CHARACTERS.add('\n');
MAPPED_CHARACTERS.add('\t');
-
+
}
-
+
/**
* {@inheritDoc}
*
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-12 20:54:55 UTC
(rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -39,6 +39,7 @@
public static I18n inputStreamConsumed;
public static I18n nonInputStreamConsumed;
public static I18n pathNotFound;
+ public static I18n pathNotFoundRelativeTo;
public static I18n permissionDenied;
public static I18n repositoryMustBeConfigured;
public static I18n sourceInUse;
@@ -61,9 +62,19 @@
public static I18n invalidRelativePath;
public static I18n invalidPathParameter;
public static I18n invalidNamePattern;
+ public static I18n noPrimaryItemNameDefinedOnPrimaryType;
+ public static I18n primaryItemNameForPrimaryTypeIsNotValid;
+ public static I18n primaryItemDoesNotExist;
public static I18n itemNotFoundWithUuid;
+ public static I18n itemNotFoundAtPath;
+ public static I18n itemNotFoundAtPathRelativeToReferenceNode;
+ public static I18n propertyNotFoundAtPathRelativeToReferenceNode;
+ public static I18n nodeNotFoundAtPathRelativeToReferenceNode;
+ public static I18n childNotFoundUnderNode;
public static I18n errorWhileFindingNodeWithUuid;
+ public static I18n errorWhileFindingNodeWithPath;
public static I18n nodeDefinitionCouldNotBeDeterminedForNode;
+ public static I18n missingNodeTypeForExistingNode;
public static I18n typeNotFound;
public static I18n supertypeNotFound;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -37,7 +37,7 @@
protected final JcrSession session;
- private final NodeType declaringNodeType;
+ protected final JcrNodeType declaringNodeType;
protected final Name name;
private final int onParentVersion;
private final boolean autoCreated;
@@ -45,7 +45,7 @@
private final boolean protectedItem;
JcrItemDefinition( JcrSession session,
- NodeType declaringNodeType,
+ JcrNodeType declaringNodeType,
Name name,
int onParentVersion,
boolean autoCreated,
@@ -54,13 +54,20 @@
super();
this.session = session;
this.declaringNodeType = declaringNodeType;
- this.name = name;
+ this.name = name != null ? name : session.getExecutionContext()
+ .getValueFactories()
+ .getNameFactory()
+
.create(JcrNodeType.RESIDUAL_ITEM_NAME);
this.onParentVersion = onParentVersion;
this.autoCreated = autoCreated;
this.mandatory = mandatory;
this.protectedItem = protectedItem;
}
+ final Name getInternalName() {
+ return name;
+ }
+
/**
* {@inheritDoc}
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -30,7 +30,6 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.PropertyDefinition;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.graph.property.Property;
@@ -40,11 +39,9 @@
@NotThreadSafe
final class JcrMultiValueProperty extends AbstractJcrProperty {
- JcrMultiValueProperty( AbstractJcrNode node,
- PropertyDefinition definition,
- int propertyType,
- Property dnaProperty ) {
- super(node, definition, propertyType, dnaProperty);
+ JcrMultiValueProperty( SessionCache cache,
+ PropertyId propertyId ) {
+ super(cache, propertyId);
}
/**
@@ -102,7 +99,7 @@
* @see javax.jcr.Property#getLengths()
*/
public long[] getLengths() throws RepositoryException {
- Property dnaProperty = getDnaProperty();
+ Property dnaProperty = propertyInfo().getProperty();
long[] lengths = new long[dnaProperty.size()];
Iterator<?> iter = dnaProperty.iterator();
for (int ndx = 0; iter.hasNext(); ndx++) {
@@ -161,8 +158,8 @@
*
* @see javax.jcr.Property#getValues()
*/
- public Value[] getValues() {
- Property dnaProperty = getDnaProperty();
+ public Value[] getValues() throws RepositoryException {
+ Property dnaProperty = propertyInfo().getProperty();
Value[] values = new JcrValue[dnaProperty.size()];
Iterator<?> iter = dnaProperty.iterator();
for (int ndx = 0; iter.hasNext(); ndx++) {
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-12 20:54:55 UTC
(rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -27,10 +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.Location;
-import org.jboss.dna.graph.property.Path;
/**
* @author jverhaeg
@@ -38,19 +35,19 @@
@NotThreadSafe
final class JcrNode extends AbstractJcrNode {
- private final UUID parentUuid;
-
- JcrNode( JcrSession session,
- UUID parentUuid,
- Location location,
- NodeDefinition nodeDefinition ) {
- super(session, location, nodeDefinition);
- assert parentUuid != null;
- this.parentUuid = parentUuid;
+ JcrNode( SessionCache cache,
+ UUID nodeUuid ) {
+ super(cache, nodeUuid);
}
- final Path.Segment segment() {
- return location.getPath().getLastSegment();
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.AbstractJcrNode#isRoot()
+ */
+ @Override
+ boolean isRoot() {
+ return false;
}
/**
@@ -58,8 +55,8 @@
*
* @see javax.jcr.Node#getIndex()
*/
- public int getIndex() {
- return segment().getIndex();
+ public int getIndex() throws RepositoryException {
+ return cache.getSnsIndexOf(nodeUuid);
}
/**
@@ -67,8 +64,8 @@
*
* @see javax.jcr.Item#getName()
*/
- public String getName() {
- return
segment().getName().getString(((JcrSession)getSession()).getExecutionContext().getNamespaceRegistry());
+ public String getName() throws RepositoryException {
+ return cache.getNameOf(nodeUuid).getString(namespaces());
}
/**
@@ -76,12 +73,8 @@
*
* @see javax.jcr.Item#getParent()
*/
- public Node getParent() throws ItemNotFoundException {
- Node node = session().getNode(parentUuid);
- if (node == null) {
- throw new ItemNotFoundException();
- }
- return node;
+ public Node getParent() throws ItemNotFoundException, RepositoryException {
+ return cache.findJcrNode(nodeInfo().getParent());
}
/**
@@ -90,20 +83,6 @@
* @see javax.jcr.Item#getPath()
*/
public String getPath() throws RepositoryException {
- Node parent = getParent();
- StringBuilder builder = new StringBuilder(parent.getPath());
- assert builder.length() > 0;
- if (builder.charAt(builder.length() - 1) != '/') {
- builder.append('/');
- }
- String name = getName();
- builder.append(name);
- int ndx = getIndex();
- if (ndx > 1) {
- builder.append('[');
- builder.append(ndx);
- builder.append(']');
- }
- return builder.toString();
+ return cache.getPathFor(nodeUuid).getString(namespaces());
}
}
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-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -47,8 +47,11 @@
/** @see NodeDefinition#getRequiredPrimaryTypes() */
private final NodeType[] requiredPrimaryTypes;
+ /** A durable identifier for this node definition. */
+ private NodeDefinitionId id;
+
JcrNodeDefinition( JcrSession session,
- NodeType declaringNodeType,
+ JcrNodeType declaringNodeType,
Name name,
int onParentVersion,
boolean autoCreated,
@@ -64,6 +67,18 @@
}
/**
+ * Get the durable identifier for this node definition.
+ *
+ * @return the node definition ID; never null
+ */
+ public NodeDefinitionId getId() {
+ if (id == null) {
+ id = new NodeDefinitionId(declaringNodeType.getInternalName(), name);
+ }
+ return id;
+ }
+
+ /**
* {@inheritDoc}
*
* @see javax.jcr.nodetype.NodeDefinition#allowsSameNameSiblings()
@@ -117,7 +132,7 @@
* @return a new <code>JcrNodeDefinition</code> that is identical to the
current object, but with the given
* <code>declaringNodeType</code>.
*/
- JcrNodeDefinition with( NodeType declaringNodeType ) {
+ JcrNodeDefinition with( JcrNodeType declaringNodeType ) {
return new JcrNodeDefinition(session, declaringNodeType, name,
getOnParentVersion(), isAutoCreated(), isMandatory(),
isProtected(), allowsSameNameSiblings(),
defaultPrimaryTypeName, requiredPrimaryTypes);
}
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-12 20:54:55 UTC
(rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -102,43 +102,113 @@
*
* @param propertyName the name of the property for which the definition should be
retrieved. Use
* {@link JcrNodeType#RESIDUAL_ITEM_NAME} to retrieve the residual property
definition (if any).
+ * @param preferMultiValued true if the property definition would prefer multiple
values, or false if single-valued definition
+ * is preferred
* @return the property definition for the given name or
<code>null</code> if no such definition exists.
* @see JcrNodeType#RESIDUAL_ITEM_NAME
*/
- JcrPropertyDefinition getPropertyDefinition( String propertyName ) {
+ JcrPropertyDefinition getPropertyDefinition( String propertyName,
+ boolean preferMultiValued ) {
+ JcrPropertyDefinition result = null;
for (JcrPropertyDefinition property : propertyDefinitions) {
if (propertyName.equals(property.getName())) {
- return property;
+ result = property;
+ if (property.isMultiple() == preferMultiValued) return result;
+ // Otherwise, keep looking for a better match ...
}
}
for (NodeType nodeType : declaredSupertypes) {
- JcrPropertyDefinition definition =
((JcrNodeType)nodeType).getPropertyDefinition(propertyName);
+ JcrPropertyDefinition definition =
((JcrNodeType)nodeType).getPropertyDefinition(propertyName, preferMultiValued);
+ if (definition != null) {
+ if (definition.isMultiple() == preferMultiValued) return definition;
+ if (result == null) result = definition;
+ }
+ }
+ return result; // may be null
+ }
+
+ /**
+ * Returns the property definition with the given name. This method first checks the
property definitions declared within this
+ * type to see if any property definitions have the given name. If no matches are
found, this method initiates a recursive
+ * depth first search up the type hierarchy to attempt to find a definition in one of
the supertypes (or one the supertypes of
+ * the supertypes).
+ *
+ * @param propertyName the name of the property for which the definition should be
retrieved. Use
+ * {@link JcrNodeType#RESIDUAL_ITEM_NAME} to retrieve the residual property
definition (if any).
+ * @param preferMultiValued true if the property definition would prefer multiple
values, or false if single-valued definition
+ * is preferred
+ * @return the property definition for the given name or
<code>null</code> if no such definition exists.
+ * @see JcrNodeType#RESIDUAL_ITEM_NAME
+ */
+ JcrPropertyDefinition getPropertyDefinition( Name propertyName,
+ boolean preferMultiValued ) {
+ JcrPropertyDefinition result = null;
+ for (JcrPropertyDefinition property : propertyDefinitions) {
+ if (propertyName.equals(property.getInternalName())) {
+ result = property;
+ if (property.isMultiple() == preferMultiValued) return result;
+ // Otherwise, keep looking for a better match ...
+ }
+ }
+
+ for (NodeType nodeType : declaredSupertypes) {
+ JcrPropertyDefinition definition =
((JcrNodeType)nodeType).getPropertyDefinition(propertyName, preferMultiValued);
+ if (definition != null) {
+ if (definition.isMultiple() == preferMultiValued) return definition;
+ if (result == null) result = definition;
+ }
+ }
+ return result; // may be null
+ }
+
+ /**
+ * Returns the child node definition with the given name. This method first checks
the child node definitions declared within
+ * this type to see if any child node definitions have the given name. If no matches
are found, this method initiates a
+ * recursive depth first search up the type hierarchy to attempt to find a definition
in one of the supertypes (or one the
+ * supertypes of the supertypes).
+ *
+ * @param childDefinitionName the name of the child node definition to be retrieved,
or a name containing
+ * {@link JcrNodeType#RESIDUAL_ITEM_NAME '*'} to retrieve the residual
child node definition (if any).
+ * @return the child node definition with the given name or
<code>null</code> if no such definition exists.
+ * @see JcrNodeType#RESIDUAL_ITEM_NAME
+ * @see #getChildNodeDefinition(Name)
+ */
+ JcrNodeDefinition getChildNodeDefinition( String childDefinitionName ) {
+ for (JcrNodeDefinition childNode : childNodeDefinitions) {
+ if (childDefinitionName.equals(childNode.getName())) {
+ return childNode;
+ }
+ }
+
+ for (NodeType nodeType : declaredSupertypes) {
+ JcrNodeDefinition definition =
((JcrNodeType)nodeType).getChildNodeDefinition(childDefinitionName);
if (definition != null) return definition;
}
return null;
}
/**
- * Returns the node definition for the child node with the given name. This method
first checks the child node definitions
- * declared within this type to see if any child node definitions have the given
name. If no matches are found, this method
- * initiates a recursive depth first search up the type hierarchy to attempt to find
a definition in one of the supertypes (or
- * one the supertypes of the supertypes).
+ * Returns the child node definition with the given name. This method first checks
the child node definitions declared within
+ * this type to see if any child node definitions have the given name. If no matches
are found, this method initiates a
+ * recursive depth first search up the type hierarchy to attempt to find a definition
in one of the supertypes (or one the
+ * supertypes of the supertypes).
*
- * @param childNodeName the name of the child node for which the definition should be
retrieved. Use
- * {@link JcrNodeType#RESIDUAL_ITEM_NAME} to retrieve the residual child node
definition (if any).
+ * @param childDefinitionName the name of the child node definition to be retrieved,
or a name containing
+ * {@link JcrNodeType#RESIDUAL_ITEM_NAME '*'} to retrieve the residual
child node definition (if any).
* @return the child node definition with the given name or
<code>null</code> if no such definition exists.
* @see JcrNodeType#RESIDUAL_ITEM_NAME
+ * @see #getChildNodeDefinition(String)
*/
- JcrNodeDefinition getChildNodeDefinition( String childNodeName ) {
+ JcrNodeDefinition getChildNodeDefinition( Name childDefinitionName ) {
for (JcrNodeDefinition childNode : childNodeDefinitions) {
- if (childNodeName.equals(childNode.getName())) {
+ if (childDefinitionName.equals(childNode.name)) {
return childNode;
}
}
for (NodeType nodeType : declaredSupertypes) {
- JcrNodeDefinition definition =
((JcrNodeType)nodeType).getChildNodeDefinition(childNodeName);
+ JcrNodeDefinition definition =
((JcrNodeType)nodeType).getChildNodeDefinition(childDefinitionName);
if (definition != null) return definition;
}
return null;
@@ -153,6 +223,7 @@
* @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
*/
+ @Deprecated
JcrNodeDefinition findBestNodeDefinitionForChild( String childName,
String primaryNodeTypeName ) {
// First, try to find a child node definition with the given name
@@ -173,6 +244,46 @@
}
/**
+ * 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( Name childName,
+ Name 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
+ boolean checkResidual = true;
+ if (childNode == null) {
+ childNode = getChildNodeDefinition(RESIDUAL_ITEM_NAME);
+ checkResidual = false;
+ }
+
+ // Check if the node can be added with the named child node definition
+ if (childNode != null && primaryNodeTypeName != null) {
+ NodeType primaryNodeType = getPrimaryNodeType(primaryNodeTypeName);
+ if (primaryNodeType == null) return null;
+ if (!checkTypeAgainstDefinition(primaryNodeType, childNode)) {
+ if (checkResidual) {
+ // Find a residual child definition ...
+ childNode = getChildNodeDefinition(RESIDUAL_ITEM_NAME);
+ if (childNode != null) {
+ // Check the residual child definition ...
+ if (checkTypeAgainstDefinition(primaryNodeType, childNode))
return childNode;
+ }
+ }
+ return null;
+ }
+ }
+ return childNode;
+ }
+
+ /**
* {@inheritDoc}
*
* @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String)
@@ -211,6 +322,10 @@
}
}
+ protected final NodeType getPrimaryNodeType( Name primaryNodeTypeName ) {
+ return session.nodeTypeManager().getNodeType(primaryNodeTypeName);
+ }
+
/**
* {@inheritDoc}
*
@@ -306,9 +421,9 @@
Value value ) {
CheckArg.isNotNull(propertyName, "propertyName");
- JcrPropertyDefinition property = getPropertyDefinition(propertyName);
+ JcrPropertyDefinition property = getPropertyDefinition(propertyName, false);
if (property == null) {
- property = getPropertyDefinition(RESIDUAL_ITEM_NAME);
+ property = getPropertyDefinition(RESIDUAL_ITEM_NAME, false);
}
if (property == null) {
@@ -324,12 +439,11 @@
if (value == null) {
return !property.isMandatory();
}
-
+
try {
assert value instanceof JcrValue : "Illegal implementation of Value
interface";
- ((JcrValue) value).asType(property.getRequiredType());
- }
- catch (javax.jcr.ValueFormatException vfe) {
+ ((JcrValue)value).asType(property.getRequiredType());
+ } catch (javax.jcr.ValueFormatException vfe) {
// Cast failed
return false;
}
@@ -345,9 +459,9 @@
Value[] values ) {
CheckArg.isNotNull(propertyName, "propertyName");
- JcrPropertyDefinition property = getPropertyDefinition(propertyName);
+ JcrPropertyDefinition property = getPropertyDefinition(propertyName, true);
if (property == null) {
- property = getPropertyDefinition(RESIDUAL_ITEM_NAME);
+ property = getPropertyDefinition(RESIDUAL_ITEM_NAME, true);
}
if (property == null) {
@@ -368,9 +482,8 @@
if (values[i] != null) {
try {
assert values[i] instanceof JcrValue : "Illegal implementation
of Value interface";
- ((JcrValue) values[i]).asType(property.getRequiredType());
- }
- catch (javax.jcr.ValueFormatException vfe) {
+ ((JcrValue)values[i]).asType(property.getRequiredType());
+ } catch (javax.jcr.ValueFormatException vfe) {
// Cast failed
return false;
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -96,7 +96,7 @@
return new JcrNodeTypeIterator(mixinNodeTypes.values());
}
- final JcrNodeType getNodeType( Name nodeTypeName ) {
+ JcrNodeType getNodeType( Name nodeTypeName ) {
JcrNodeType nodeType = primaryNodeTypes.get(nodeTypeName);
if (nodeType == null) {
@@ -141,4 +141,32 @@
return null;
}
+ /**
+ * Get the node definition given the supplied identifier.
+ *
+ * @param definitionId the identifier of the node definition
+ * @return the node definition, or null if there is no such definition (or if the ID
was null)
+ */
+ JcrNodeDefinition getNodeDefinition( NodeDefinitionId definitionId ) {
+ if (definitionId == null) return null;
+ Name nodeTypeName = definitionId.getNodeTypeName();
+ JcrNodeType nodeType = getNodeType(nodeTypeName);
+ return nodeType.getChildNodeDefinition(definitionId.getChildDefinitionName());
+ }
+
+ /**
+ * Get the property definition given the supplied identifier.
+ *
+ * @param definitionId the identifier of the node definition
+ * @param prefersMultiValued true if the property should be a multi-valued, or false
if it should be single-valued
+ * @return the node definition, or null if there is no such definition (or if the ID
was null)
+ */
+ JcrPropertyDefinition getPropertyDefinition( PropertyDefinitionId definitionId,
+ boolean prefersMultiValued ) {
+ if (definitionId == null) return null;
+ Name nodeTypeName = definitionId.getNodeTypeName();
+ JcrNodeType nodeType = getNodeType(nodeTypeName);
+ return nodeType.getPropertyDefinition(definitionId.getPropertyDefinitionName(),
prefersMultiValued);
+ }
+
}
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-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -24,15 +24,13 @@
package org.jboss.dna.jcr;
import javax.jcr.Value;
-import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.property.Name;
-
/**
- * DNA implementation of the {@link PropertyDefinition} interface. This implementation
is immutable and has all fields initialized
- * through its constructor.
+ * DNA implementation of the {@link PropertyDefinition} interface. This implementation is
immutable and has all fields initialized
+ * through its constructor.
*/
@Immutable
class JcrPropertyDefinition extends JcrItemDefinition implements PropertyDefinition {
@@ -41,9 +39,10 @@
private final int requiredType;
private final String[] valueConstraints;
private final boolean multiple;
+ private PropertyDefinitionId id;
JcrPropertyDefinition( JcrSession session,
- NodeType declaringNodeType,
+ JcrNodeType declaringNodeType,
Name name,
int onParentVersion,
boolean autoCreated,
@@ -61,6 +60,18 @@
}
/**
+ * Get the durable identifier for this property definition.
+ *
+ * @return the property definition ID; never null
+ */
+ public PropertyDefinitionId getId() {
+ if (id == null) {
+ id = new PropertyDefinitionId(declaringNodeType.getInternalName(), name);
+ }
+ return id;
+ }
+
+ /**
* {@inheritDoc}
*
* @see javax.jcr.nodetype.PropertyDefinition#getDefaultValues()
@@ -104,7 +115,7 @@
* @return a new <code>JcrPropertyDefinition</code> that is identical to
the current object, but with the given
* <code>declaringNodeType</code>.
*/
- JcrPropertyDefinition with( NodeType declaringNodeType ) {
+ JcrPropertyDefinition with( JcrNodeType declaringNodeType ) {
return new JcrPropertyDefinition(this.session, declaringNodeType, this.name,
this.getOnParentVersion(),
this.isAutoCreated(), this.isMandatory(),
this.isProtected(), this.getDefaultValues(),
this.getRequiredType(),
this.getValueConstraints(), this.isMultiple());
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -31,16 +31,15 @@
import org.jboss.dna.common.util.CheckArg;
/**
- * @author jverhaeg
*/
@Immutable
final class JcrPropertyIterator implements PropertyIterator {
- private final Iterator<Property> iterator;
+ private final Iterator<? extends Property> iterator;
private int ndx;
private int size;
- JcrPropertyIterator( Collection<Property> properties ) {
+ JcrPropertyIterator( Collection<? extends Property> properties ) {
assert properties != null;
iterator = properties.iterator();
size = properties.size();
@@ -88,9 +87,9 @@
* @see javax.jcr.PropertyIterator#nextProperty()
*/
public Property nextProperty() {
- Property property = iterator.next();
+ Property next = iterator.next();
ndx++;
- return property;
+ return next;
}
/**
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-12 20:54:55 UTC
(rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -23,11 +23,12 @@
*/
package org.jboss.dna.jcr;
+import java.util.UUID;
+import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
-import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.RepositoryException;
import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.graph.Location;
/**
* @author jverhaeg
@@ -35,15 +36,24 @@
@NotThreadSafe
final class JcrRootNode extends AbstractJcrNode {
- JcrRootNode( JcrSession session,
- Location location,
- NodeDefinition nodeDefinition ) {
- super(session, location, nodeDefinition);
+ JcrRootNode( SessionCache cache,
+ UUID nodeUuid ) {
+ super(cache, nodeUuid);
}
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.jcr.AbstractJcrNode#isRoot()
+ */
+ @Override
+ boolean isRoot() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @return 0;
* @see javax.jcr.Item#getDepth()
*/
@@ -91,4 +101,18 @@
public String getPath() {
return "/";
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.AbstractJcrItem#getAncestor(int)
+ */
+ @Override
+ public final Item getAncestor( int depth ) throws RepositoryException {
+ if (depth == 0) return this;
+ if (depth < 0) {
+ throw new ItemNotFoundException(JcrI18n.noNegativeDepth.text(depth));
+ }
+ throw new ItemNotFoundException(JcrI18n.tooDeep.text(depth));
+ }
}
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-12 20:54:55 UTC
(rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -28,11 +28,6 @@
import java.security.AccessControlException;
import java.security.Principal;
import java.util.Calendar;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -42,7 +37,6 @@
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
@@ -51,10 +45,6 @@
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;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
@@ -62,20 +52,14 @@
import org.jboss.dna.common.util.CheckArg;
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;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.ValueFactories;
-import org.jboss.dna.graph.property.ValueFormatException;
import org.jboss.dna.graph.property.basic.LocalNamespaceRegistry;
import org.jboss.dna.jcr.JcrNamespaceRegistry.Behavior;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
-import com.google.common.base.ReferenceType;
-import com.google.common.collect.ReferenceMap;
/**
* @author John Verhaeg
@@ -84,12 +68,6 @@
@NotThreadSafe
class JcrSession implements Session {
- /**
- * Hidden flag that controls whether properties that appear on DNA nodes but not
allowed by the node type or mixins should be
- * included anyway. This is currently {@value} .
- */
- private static final boolean INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS =
true;
-
private static final String[] NO_ATTRIBUTES_NAMES = new String[] {};
/**
@@ -114,21 +92,23 @@
protected final ExecutionContext executionContext;
/**
+ * The session-specific attributes that came from the {@link SimpleCredentials}'
{@link SimpleCredentials#getAttributeNames()}
+ */
+ private final Map<String, Object> sessionAttributes;
+
+ /**
* The graph representing this session, which uses the {@link #graph session's
graph}.
*/
private final Graph graph;
+ private final SessionCache cache;
+
/**
- * The session-specific attributes that came from the {@link SimpleCredentials}'
{@link SimpleCredentials#getAttributeNames()}
+ * A cached instance of the root path.
*/
- private final Map<String, Object> sessionAttributes;
+ private final Path rootPath;
- private final ReferenceMap<UUID, AbstractJcrNode> nodesByUuid;
- private final ReferenceMap<String, AbstractJcrNode> nodesByJcrUuid;
private boolean isLive;
- private JcrRootNode rootNode;
- private PropertyDefinition anyMultiplePropertyDefinition;
- private transient org.jboss.dna.graph.property.Property defaultPrimaryType;
JcrSession( JcrRepository repository,
JcrWorkspace workspace,
@@ -147,14 +127,15 @@
NamespaceRegistry local = new LocalNamespaceRegistry(workspaceRegistry);
this.executionContext = workspaceContext.with(local);
this.sessionRegistry = new JcrNamespaceRegistry(Behavior.JSR170_SESSION, local,
workspaceRegistry);
+ this.rootPath =
this.executionContext.getValueFactories().getPathFactory().createRootPath();
// Set up the graph to use for this session (which uses the session's
namespace registry and context) ...
this.graph = Graph.create(this.repository.getRepositorySourceName(),
this.repository.getConnectionFactory(),
this.executionContext);
- this.nodesByUuid = new ReferenceMap<UUID,
AbstractJcrNode>(ReferenceType.STRONG, ReferenceType.SOFT);
- this.nodesByJcrUuid = new ReferenceMap<String,
AbstractJcrNode>(ReferenceType.STRONG, ReferenceType.SOFT);
+ this.cache = new SessionCache(this, workspace.getName(), this.executionContext,
this.workspace.nodeTypeManager(),
+ this.graph);
this.isLive = true;
assert this.repository != null;
@@ -169,24 +150,15 @@
return this.executionContext;
}
- final JcrNodeTypeManager nodeTypeManager() {
+ JcrNodeTypeManager nodeTypeManager() {
return this.workspace.nodeTypeManager();
}
- final NamespaceRegistry namespaces() {
+ NamespaceRegistry namespaces() {
return this.executionContext.getNamespaceRegistry();
}
/**
- * Return an unmodifiable map of nodes given then UUID.
- *
- * @return nodesByUuid
- */
- Map<UUID, AbstractJcrNode> getNodesByUuid() {
- return Collections.unmodifiableMap(nodesByUuid);
- }
-
- /**
* {@inheritDoc}
*
* @see javax.jcr.Session#getWorkspace()
@@ -417,21 +389,6 @@
throw new UnsupportedOperationException();
}
- Node getChild( AbstractJcrNode parent,
- Location location ) throws RepositoryException {
- Node child = null;
- UUID uuid = location.getUuid();
- if (uuid != null) {
- // The location has a UUID, so look up the node by this UUID in the session
...
- child = getNode(uuid);
- }
- if (child == null) {
- // The child was not found in the session's cache, so create the node
using its path ...
- child = loadNode(parent, location.getPath());
- }
- return child;
- }
-
/**
* Find or create a JCR Node for the given path. This method works for the root node,
too.
*
@@ -441,212 +398,25 @@
* @throws RepositoryException if there is a problem
*/
Node getNode( Path path ) throws RepositoryException, PathNotFoundException {
- if (path.isRoot()) return rootNode();
-
- // Start at the root and walk down the path ...
- AbstractJcrNode parent = rootNode();
- AbstractJcrNode node = null;
- Iterator<Path> pathIter = path.pathsFromRoot();
- while (pathIter.hasNext()) {
- node = loadNode(parent, pathIter.next()); // should throw
PathNotFoundException if not there
- parent = node;
- }
- return node;
+ return cache.findJcrNode(null, path.relativeTo(rootPath));
}
/**
- * Find or create a JCR Node for the given path. This method works for the root node,
too.
- *
- * @param parent the parent of the node, if known; null if the parent is not known
- * @param path the path; may not be null
- * @return the JCR node instance for the given path; never null
- * @throws PathNotFoundException if the path could not be found
- * @throws RepositoryException if there is a problem
- */
- private AbstractJcrNode loadNode( AbstractJcrNode parent,
- Path path ) throws RepositoryException,
PathNotFoundException {
- 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 = null;
- try {
- graphNode = graph.getNodeAt(path);
- } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
- // If the node isn't found, throw a PathNotFoundException
- throw new PathNotFoundException(JcrI18n.pathNotFound.text(path));
- }
-
- // 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) {
- // Check for an existing node at this UUID ...
- AbstractJcrNode existing = nodesByUuid.get(uuid);
- if (existing != null) return existing;
-
- // 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) {
- AbstractJcrNode node = getNode(uuid);
- 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);
- }
- 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, location, definition);
- } else {
- // Find the parent ...
- if (parent == null) {
- parent = (AbstractJcrNode)getNode(path.getParent());
- }
- assert parent != null;
-
- // 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.nodeDefinitionCouldNotBeDeterminedForNode.text(path, workspace.getName());
- throw new RepositorySourceException(msg);
- }
- }
-
- // Now create the node object ...
- node = new JcrNode(this, parent.internalUuid(), location, definition);
- }
-
- // Now populate the node and add to the cache ...
- populateNode(node, graphNode, uuid, uuidProperty, primaryTypeProperty);
- if (isRoot) rootNode = (JcrRootNode)node;
- return node;
- }
-
- AbstractJcrNode getNode( UUID uuid ) {
- return nodesByUuid.get(uuid);
- }
-
- /**
* {@inheritDoc}
*
* @see javax.jcr.Session#getNodeByUUID(java.lang.String)
*/
public Node getNodeByUUID( String uuid ) throws ItemNotFoundException,
RepositoryException {
- Node result = null;
- try {
- result = nodesByUuid.get(UUID.fromString(uuid));
- } catch (IllegalArgumentException e) {
- throw new ItemNotFoundException(JcrI18n.itemNotFoundWithUuid.text(uuid,
workspace.getName()));
- } catch (Throwable e) {
- throw new
RepositoryException(JcrI18n.errorWhileFindingNodeWithUuid.text(uuid,
workspace.getName()));
- }
- if (result == null) {
- throw new ItemNotFoundException(JcrI18n.itemNotFoundWithUuid.text(uuid,
workspace.getName()));
- }
- return result;
+ return cache.findJcrNode(UUID.fromString(uuid));
}
- JcrRootNode rootNode() throws RepositoryException {
- // Return cached root node if available
- if (rootNode != null) {
- return rootNode;
- }
- Path rootPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
- loadNode(null, rootPath); // sets the root node
- assert rootNode != null;
- return rootNode;
- }
-
/**
* {@inheritDoc}
*
* @see javax.jcr.Session#getRootNode()
*/
public Node getRootNode() throws RepositoryException {
- return rootNode();
+ return cache.findJcrRootNode();
}
/**
@@ -842,187 +612,6 @@
return PropertyType.UNDEFINED;
}
- 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
- // --------------------------------------------------
- node.setChildren(graphNode.getChildren());
-
- // ------------------------------------------------------
- // Create JCR properties for corresponding DNA properties
- // ------------------------------------------------------
- // First get the property type for each property, based upon the primary type and
mixins ...
- // The map with single-valued properties...
- Map<Name, PropertyDefinition> svPropertyDefinitionsByPropertyName = new
HashMap<Name, PropertyDefinition>();
- // ... and the map with multi-valued properties
- Map<Name, PropertyDefinition> mvPropertyDefinitionsByPropertyName = new
HashMap<Name, PropertyDefinition>();
-
-
- boolean referenceable = false;
-
- NamespaceRegistry registry = namespaces();
- ValueFactories factories = executionContext.getValueFactories();
- NameFactory nameFactory = factories.getNameFactory();
- NodeTypeManager nodeTypeManager = getWorkspace().getNodeTypeManager();
- List<PropertyDefinition> anyPropertyDefinitions = new
LinkedList<PropertyDefinition>();
- // 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);
-
- if (propertyDefn.isMultiple()) {
- PropertyDefinition prev = mvPropertyDefinitionsByPropertyName.put(name,
propertyDefn);
- if (prev != null) mvPropertyDefinitionsByPropertyName.put(name, prev); //
put the first one back ...
- }
- else {
- PropertyDefinition prev = svPropertyDefinitionsByPropertyName.put(name,
propertyDefn);
- if (prev != null) svPropertyDefinitionsByPropertyName.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 mixinType = nodeTypeManager.getNodeType(mixinTypeNameString);
- for (PropertyDefinition propertyDefn :
mixinType.getPropertyDefinitions()) {
- String nameString = propertyDefn.getName();
- if ("*".equals(nameString)) {
- anyPropertyDefinitions.add(propertyDefn);
- continue;
- }
- Name name = nameFactory.create(nameString);
- if (propertyDefn.isMultiple()) {
- PropertyDefinition prev =
mvPropertyDefinitionsByPropertyName.put(name, propertyDefn);
- if (prev != null) mvPropertyDefinitionsByPropertyName.put(name,
prev); // put the first one back ...
- }
- else {
- PropertyDefinition prev =
svPropertyDefinitionsByPropertyName.put(name, propertyDefn);
- if (prev != null) svPropertyDefinitionsByPropertyName.put(name,
prev); // put the first one back ...
- }
- }
- }
- }
-
- // Now create the JCR property object wrapper around the "jcr:uuid"
property ...
- Map<Name, Property> properties = new HashMap<Name, Property>();
- if (referenceable) {
- // We know that this property is single-valued
- PropertyDefinition propertyDefinition =
svPropertyDefinitionsByPropertyName.get(JcrLexicon.UUID);
- properties.put(JcrLexicon.UUID, new JcrSingleValueProperty(node,
propertyDefinition, PropertyType.STRING,
- uuidProperty));
- }
-
- // Now create the JCR property object wrappers around the other properties ...
- for (org.jboss.dna.graph.property.Property dnaProp : graphNode.getProperties())
{
- Name name = dnaProp.getName();
-
- // Skip the JCR and DNA UUID properties (using the EXACT Name instances on
the Property) ...
- if (JcrLexicon.UUID.equals(name) || DnaLexicon.UUID.equals(name)) continue;
-
- // Figure out the JCR property type for this property ...
- PropertyDefinition propertyDefinition;
-
- if (dnaProp.isMultiple()) {
- propertyDefinition = mvPropertyDefinitionsByPropertyName.get(name);
- }
- else {
- propertyDefinition = svPropertyDefinitionsByPropertyName.get(name);
-
- // If the property has only one value, dnaProp.isMultiple() will return
false, but the
- // property may actually be a multi-valued property that happens to have
one property set.
- if (propertyDefinition == null) {
- propertyDefinition = mvPropertyDefinitionsByPropertyName.get(name);
- }
- }
-
- // If no property type was found for this property, see if there is a
wildcard property ...
- if (propertyDefinition == null) {
- for (Iterator<PropertyDefinition> iter =
anyPropertyDefinitions.iterator(); iter.hasNext(); ) {
- PropertyDefinition nextDef = iter.next();
-
- // Grab the first residual definition that matches on cardinality
(single-valued vs. multi-valued)
- if ((nextDef.isMultiple() && dnaProp.isMultiple())
- || (!nextDef.isMultiple() && !dnaProp.isMultiple())) {
- propertyDefinition = nextDef;
- break;
- }
- }
- }
-
-
- // If there still is no property type defined ...
- if (propertyDefinition == null) {
- assert anyPropertyDefinitions.isEmpty();
- if (INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS) {
- // We can use the "nt:unstructured" property definitions
for any property ...
- if (anyMultiplePropertyDefinition == null) {
- String unstructuredName =
JcrNtLexicon.UNSTRUCTURED.getString(registry);
- NodeType unstructured =
nodeTypeManager.getNodeType(unstructuredName);
- for (PropertyDefinition definition :
unstructured.getDeclaredPropertyDefinitions()) {
- if (definition.isMultiple()) {
- anyMultiplePropertyDefinition = definition;
- }
- }
- }
- propertyDefinition = anyMultiplePropertyDefinition;
- }
- }
- if (propertyDefinition == null) {
- // We're supposed to skip this property (since we don't have a
definition for it) ...
- continue;
- }
-
- // Figure out if this is a multi-valued property ...
- boolean isMultiple = propertyDefinition.isMultiple();
- if (!isMultiple && dnaProp.isEmpty()) {
- // Only multi-valued properties can have no values; so if not
multi-valued, then skip ...
- continue;
- }
-
- // Figure out the property type ...
- int propertyType = propertyDefinition.getRequiredType();
- if (propertyType == PropertyType.UNDEFINED) {
- propertyType = jcrPropertyTypeFor(dnaProp);
- }
-
- // Create the appropriate JCR property wrapper ...
- if (isMultiple) {
- properties.put(name, new JcrMultiValueProperty(node, propertyDefinition,
propertyType, dnaProp));
- } else {
- properties.put(name, new JcrSingleValueProperty(node, propertyDefinition,
propertyType, dnaProp));
- }
- }
-
- // Now set the properties on the node ...
- node.setProperties(properties);
-
- // Set node's UUID, creating one if necessary
- nodesByJcrUuid.put(uuid.toString(), node);
- node.setInternalUuid(uuid);
- // Setup node to be retrieved by DNA UUID
- nodesByUuid.put(uuid, node);
- }
-
/**
* {@inheritDoc}
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -30,9 +30,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.PropertyDefinition;
import org.jboss.dna.graph.property.Binary;
-import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.property.Reference;
import org.jboss.dna.graph.property.ValueFactories;
@@ -41,11 +39,9 @@
*/
final class JcrSingleValueProperty extends AbstractJcrProperty {
- JcrSingleValueProperty( AbstractJcrNode node,
- PropertyDefinition definition,
- int propertyType,
- Property dnaProperty ) {
- super(node, definition, propertyType, dnaProperty);
+ JcrSingleValueProperty( SessionCache cache,
+ PropertyId propertyId ) {
+ super(cache, propertyId);
}
/**
@@ -55,7 +51,7 @@
*/
public boolean getBoolean() throws RepositoryException {
try {
- return
getExecutionContext().getValueFactories().getBooleanFactory().create(getDnaProperty().getFirstValue());
+ return
context().getValueFactories().getBooleanFactory().create(property().getFirstValue());
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -68,10 +64,7 @@
*/
public Calendar getDate() throws RepositoryException {
try {
- return getExecutionContext().getValueFactories()
- .getDateFactory()
- .create(getDnaProperty().getFirstValue())
- .toCalendar();
+ return
context().getValueFactories().getDateFactory().create(property().getFirstValue()).toCalendar();
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -84,7 +77,7 @@
*/
public double getDouble() throws RepositoryException {
try {
- return
getExecutionContext().getValueFactories().getDoubleFactory().create(getDnaProperty().getFirstValue());
+ return
context().getValueFactories().getDoubleFactory().create(property().getFirstValue());
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -96,7 +89,7 @@
* @see javax.jcr.Property#getLength()
*/
public long getLength() throws RepositoryException {
- return createValue(getDnaProperty().getFirstValue()).getLength();
+ return createValue(property().getFirstValue()).getLength();
}
/**
@@ -116,7 +109,7 @@
*/
public long getLong() throws RepositoryException {
try {
- return
getExecutionContext().getValueFactories().getLongFactory().create(getDnaProperty().getFirstValue());
+ return
context().getValueFactories().getLongFactory().create(property().getFirstValue());
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -129,10 +122,10 @@
*/
public final Node getNode() throws RepositoryException {
try {
- ValueFactories factories = getExecutionContext().getValueFactories();
- Reference dnaReference =
factories.getReferenceFactory().create(getDnaProperty().getFirstValue());
+ ValueFactories factories = context().getValueFactories();
+ Reference dnaReference =
factories.getReferenceFactory().create(property().getFirstValue());
UUID uuid = factories.getUuidFactory().create(dnaReference);
- return ((JcrSession)getSession()).getNode(uuid);
+ return cache.findJcrNode(uuid);
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -145,7 +138,7 @@
*/
public InputStream getStream() throws RepositoryException {
try {
- Binary binary =
getExecutionContext().getValueFactories().getBinaryFactory().create(getDnaProperty().getFirstValue());
+ Binary binary =
context().getValueFactories().getBinaryFactory().create(property().getFirstValue());
return new SelfClosingInputStream(binary);
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
@@ -159,7 +152,7 @@
*/
public String getString() throws RepositoryException {
try {
- return
getExecutionContext().getValueFactories().getStringFactory().create(getDnaProperty().getFirstValue());
+ return
context().getValueFactories().getStringFactory().create(property().getFirstValue());
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -170,8 +163,8 @@
*
* @see javax.jcr.Property#getValue()
*/
- public Value getValue() {
- return createValue(getDnaProperty().getFirstValue());
+ public Value getValue() throws RepositoryException {
+ return createValue(property().getFirstValue());
}
/**
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-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSystemViewExporter.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -114,7 +114,7 @@
AbstractJcrProperty prop = (AbstractJcrProperty)property;
- Name propertyName = prop.getDnaProperty().getName();
+ Name propertyName = prop.name();
if (SPECIAL_PROPERTY_NAMES.contains(propertyName)) {
return;
}
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-12 20:54:55
UTC (rev 776)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-03-16 22:50:09
UTC (rev 777)
@@ -148,10 +148,10 @@
this.session = new JcrSession(this.repository, this, this.context,
sessionAttributes);
// This must be initialized after the session
- this.nodeTypeManager = new JcrNodeTypeManager(this.session,
- new
DnaBuiltinNodeTypeSource(this.session,
- new
JcrBuiltinNodeTypeSource(this.session)));
-
+ JcrNodeTypeSource source = null;
+ source = new JcrBuiltinNodeTypeSource(this.session);
+ source = new DnaBuiltinNodeTypeSource(this.session, source);
+ this.nodeTypeManager = new JcrNodeTypeManager(this.session, source);
}
final String getSourceName() {
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -0,0 +1,164 @@
+/*
+ * 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.io.Serializable;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+
+/**
+ * An immutable identifier for a node definition. Although instances can be serialized,
the node definitions are often 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.
+ */
+@Immutable
+public final class NodeDefinitionId implements Serializable {
+
+ /**
+ * Current version is {@value} .
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The string-form of the name that can be used to represent a residual property
definition.
+ */
+ public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
+
+ private final Name nodeTypeName;
+ private final Name childDefinitionName;
+ private final int hc;
+
+ /**
+ * Create an identifier for a node definition.
+ *
+ * @param nodeTypeName the name of the node type on which this child node definition
is defined; may not be null
+ * @param childDefinitionName the name of the child node definition, which may be a
{@link #ANY_NAME residual child
+ * definition}; may not be null
+ */
+ public NodeDefinitionId( Name nodeTypeName,
+ Name childDefinitionName ) {
+ assert nodeTypeName != null;
+ assert childDefinitionName != null;
+ this.nodeTypeName = nodeTypeName;
+ this.childDefinitionName = childDefinitionName;
+ this.hc = HashCode.compute(this.nodeTypeName, this.childDefinitionName);
+ }
+
+ /**
+ * Get the name of the node type on which the child node definition is defined.
+ *
+ * @return the node type's name; never null
+ */
+ public Name getNodeTypeName() {
+ return nodeTypeName;
+ }
+
+ /**
+ * Get the name of the child definition.
+ *
+ * @return the child definition's name; never null
+ */
+ public Name getChildDefinitionName() {
+ return childDefinitionName;
+ }
+
+ /**
+ * Determine whether this node definition defines any named child.
+ *
+ * @return true if this node definition allows children with any name, or false if
this definition requires a particular child
+ * name
+ */
+ public boolean allowsAnyChildName() {
+ return childDefinitionName.getLocalName().equals(ANY_NAME) &&
childDefinitionName.getNamespaceUri().length() == 0;
+ }
+
+ /**
+ * Get the string form of this identifier. This form can be persisted, since it does
not rely upon namespace prefixes.
+ *
+ * @return the string form
+ */
+ public String getString() {
+ return this.nodeTypeName.getString() + '/' +
this.childDefinitionName.getString();
+ }
+
+ /**
+ * Parse the supplied string for of an identifer, and return the object form for that
identifier.
+ *
+ * @param definition the {@link #getString() string form of the identifier}; may not
be null
+ * @param factory the factory that should be used to create Name objects; may not be
null
+ * @return the object form of the identifier; never null
+ * @throws ValueFormatException if the definition is not the valid format
+ */
+ public static NodeDefinitionId fromString( String definition,
+ NameFactory factory ) {
+ int index = definition.indexOf('/');
+ String nodeTypeNameString = definition.substring(0, index);
+ String childDefinitionNameString = definition.substring(index + 1);
+ Name nodeTypeName = factory.create(nodeTypeNameString);
+ Name childDefinitionName = factory.create(childDefinitionNameString);
+ return new NodeDefinitionId(nodeTypeName, childDefinitionName);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof NodeDefinitionId) {
+ NodeDefinitionId that = (NodeDefinitionId)obj;
+ if (this.hc != that.hc) return false;
+ if (!this.nodeTypeName.equals(that.nodeTypeName)) return false;
+ return this.childDefinitionName.equals(that.childDefinitionName);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.nodeTypeName.toString() + '/' +
this.childDefinitionName.toString();
+ }
+
+}
Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -0,0 +1,162 @@
+/*
+ * 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.io.Serializable;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+
+/**
+ * An immutable identifier for a property definition. Although instances can be
serialized, the property definitions are often
+ * 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.
+ */
+@Immutable
+public final class PropertyDefinitionId implements Serializable {
+
+ /**
+ * Current version is {@value} .
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The string-form of the name that can be used to represent a residual property
definition.
+ */
+ public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
+
+ private final Name nodeTypeName;
+ private final Name propertyDefinitionName;
+ private final int hc;
+
+ /**
+ * Create a new identifier for a propety definition.
+ *
+ * @param nodeTypeName the name of the node type; may not be null
+ * @param propertyDefinitionName the name of the property definition, which may be a
{@link #ANY_NAME residual property}; may
+ * not be null
+ */
+ public PropertyDefinitionId( Name nodeTypeName,
+ Name propertyDefinitionName ) {
+ this.nodeTypeName = nodeTypeName;
+ this.propertyDefinitionName = propertyDefinitionName;
+ this.hc = HashCode.compute(this.nodeTypeName, this.propertyDefinitionName);
+ }
+
+ /**
+ * Get the name of the node type on which the property definition is defined
+ *
+ * @return the node type's name; may not be null
+ */
+ public Name getNodeTypeName() {
+ return nodeTypeName;
+ }
+
+ /**
+ * Get the name of the property definition.
+ *
+ * @return the property definition's name; never null
+ */
+ public Name getPropertyDefinitionName() {
+ return propertyDefinitionName;
+ }
+
+ /**
+ * Determine whether this property definition allows properties with any name.
+ *
+ * @return true if this node definition allows properties with any name, or false if
this definition requires a particular
+ * property name
+ */
+ public boolean allowsAnyChildName() {
+ return propertyDefinitionName.getLocalName().equals(ANY_NAME) &&
propertyDefinitionName.getNamespaceUri().length() == 0;
+ }
+
+ /**
+ * Get the string form of this identifier. This form can be persisted, since it does
not rely upon namespace prefixes.
+ *
+ * @return the string form
+ */
+ public String getString() {
+ return this.nodeTypeName.getString() + '/' +
this.propertyDefinitionName.getString();
+ }
+
+ /**
+ * Parse the supplied string for of an identifer, and return the object form for that
identifier.
+ *
+ * @param definition the {@link #getString() string form of the identifier}; may not
be null
+ * @param factory the factory that should be used to create Name objects; may not be
null
+ * @return the object form of the identifier; never null
+ * @throws ValueFormatException if the definition is not the valid format
+ */
+ public static PropertyDefinitionId fromString( String definition,
+ NameFactory factory ) {
+ int index = definition.indexOf('/');
+ String nodeTypeNameString = definition.substring(0, index);
+ String propertyDefinitionNameString = definition.substring(index + 1);
+ Name nodeTypeName = factory.create(nodeTypeNameString);
+ Name propertyDefinitionName = factory.create(propertyDefinitionNameString);
+ return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyDefinitionId) {
+ PropertyDefinitionId that = (PropertyDefinitionId)obj;
+ if (this.hc != that.hc) return false;
+ if (!this.nodeTypeName.equals(that.nodeTypeName)) return false;
+ return this.propertyDefinitionName.equals(that.propertyDefinitionName);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.nodeTypeName.toString() + '/' +
this.propertyDefinitionName.toString();
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -0,0 +1,111 @@
+/*
+ * 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.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+
+/**
+ * An immutable identifier for a property, often used to reference information a property
held within the {@link SessionCache}.
+ */
+@Immutable
+public final class PropertyId {
+
+ private final UUID nodeId;
+ private final Name propertyName;
+ private final int hc;
+
+ /**
+ * Create a new property identifier.
+ *
+ * @param nodeId the UUID of the node that owns the property being reference; may not
be null
+ * @param propertyName the name of the property being referenced; may not be null
+ */
+ public PropertyId( UUID nodeId,
+ Name propertyName ) {
+ assert nodeId != null;
+ assert propertyName != null;
+ this.nodeId = nodeId;
+ this.propertyName = propertyName;
+ this.hc = HashCode.compute(this.nodeId, this.propertyName);
+ }
+
+ /**
+ * Get the UUID of the node that owns the property.
+ *
+ * @return the node's UUID; never null
+ */
+ public UUID getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * Get the name of the property.
+ *
+ * @return the property name; never null
+ */
+ public Name getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyId) {
+ PropertyId that = (PropertyId)obj;
+ if (this.hc != that.hc) return false;
+ if (!this.nodeId.equals(that.nodeId)) return false;
+ return this.propertyName.equals(that.propertyName);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.nodeId.toString() + '@' + this.propertyName.toString();
+ }
+
+}
Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-03-16 22:50:09
UTC (rev 777)
@@ -0,0 +1,1583 @@
+/*
+ * 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.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+import net.jcip.annotations.Immutable;
+import net.jcip.annotations.NotThreadSafe;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Results;
+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;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.ValueFactories;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+import com.google.common.base.ReferenceType;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.ReferenceMap;
+
+/**
+ * The class that manages the session's information that has been locally-cached
after reading from the underlying {@link Graph
+ * repository} or modified by the session but not yet saved or commited to the
repository.
+ * <p>
+ * The cached information is broken into several different categories that are each
described below.
+ * </p>
+ * <h3>JCR API objects</h3>
+ * <p>
+ * Clients using the DNA JCR implementation obtain a {@link JcrSession JCR Session}
(which generally owns this cache instance) as
+ * well as the JCR {@link JcrNode Node} and {@link AbstractJcrProperty Property}
instances. This cache ensures that the same JCR
+ * Node or Property objects are always returned for the same item in the repository,
ensuring that the "==" operator always holds
+ * true for the same item. However, as soon as all (client) references to these objects
are garbage collected, this class is free
+ * to also release those objects and, when needed, recreate new implementation objects.
+ * </p>
+ * <p>
+ * This approach helps reduce memory utilization since any unused items are available for
garbage collection, but it also
+ * guarantees that once a client maintains a reference to an item, the same Java object
will always be used for any references to
+ * that item.
+ * </p>
+ * <h3>Cached nodes</h3>
+ * <p>
+ * The session cache is also responsible for maintaining a local cache of node
information retrieved from the underlying
+ * repository, reducing the need to request information any more than necessary. This
information includes that obtained directly
+ * from the repository store, including node properties, children, and references to the
parent. It also includes computed
+ * information, such as the NodeDefinition for a node, the name of the primary type and
mixin types, and the original
+ * {@link Location} of the node in the repository.
+ * </p>
+ * <h3>Transient changes</h3>
+ * <p>
+ * Any time content is changed in the session, those changes are held within the session
until they are saved either by
+ * {@link Session#save() saving the session} or {@link Item#save() saving an individual
item} (which includes any content below
+ * that item). This cache maintains all these transient changes, and when requested will
send the change requests down the
+ * repository. At any point, these transient changes may be rolled back (or
"released"), again either for the
+ * {@link Session#refresh(boolean) whole session} or for {@link Item#refresh(boolean)
individual items}.
+ * </p>
+ */
+@ThreadSafe
+public class SessionCache {
+
+ /**
+ * Hidden flag that controls whether properties that appear on DNA nodes but not
allowed by the node type or mixins should be
+ * included anyway. This is currently {@value} .
+ */
+ private static final boolean INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS =
true;
+
+ private final JcrSession session;
+ private final String workspaceName;
+ protected final ExecutionContext context;
+ protected final PathFactory pathFactory;
+ private final NameFactory nameFactory;
+ private final ValueFactory<String> stringFactory;
+ private final NamespaceRegistry namespaces;
+ private final PropertyFactory propertyFactory;
+ private final Graph store;
+ private final Name defaultPrimaryTypeName;
+ private final Property defaultPrimaryTypeProperty;
+ private final Path rootPath;
+
+ private UUID root;
+ private final ReferenceMap<UUID, AbstractJcrNode> jcrNodes;
+ private final ReferenceMap<PropertyId, AbstractJcrProperty> jcrProperties;
+
+ private final HashMap<UUID, NodeInfo> cachedNodes;
+ private final HashMap<UUID, NodeInfo> changedNodes;
+
+ public SessionCache( JcrSession session,
+ String workspaceName,
+ ExecutionContext context,
+ JcrNodeTypeManager nodeTypes,
+ Graph store ) {
+ assert session != null;
+ assert workspaceName != null;
+ assert context != null;
+ assert store != null;
+ this.session = session;
+ this.workspaceName = workspaceName;
+ this.store = store;
+ this.context = context;
+ this.pathFactory = context.getValueFactories().getPathFactory();
+ this.nameFactory = context.getValueFactories().getNameFactory();
+ this.stringFactory = context.getValueFactories().getStringFactory();
+ this.namespaces = context.getNamespaceRegistry();
+ this.propertyFactory = context.getPropertyFactory();
+ this.defaultPrimaryTypeName = JcrNtLexicon.UNSTRUCTURED;
+ this.defaultPrimaryTypeProperty = propertyFactory.create(JcrLexicon.PRIMARY_TYPE,
this.defaultPrimaryTypeName);
+ this.rootPath = pathFactory.createRootPath();
+
+ this.jcrNodes = new ReferenceMap<UUID,
AbstractJcrNode>(ReferenceType.STRONG, ReferenceType.SOFT);
+ this.jcrProperties = new ReferenceMap<PropertyId,
AbstractJcrProperty>(ReferenceType.STRONG, ReferenceType.SOFT);
+
+ this.cachedNodes = new HashMap<UUID, NodeInfo>();
+ this.changedNodes = new HashMap<UUID, NodeInfo>();
+ }
+
+ JcrSession session() {
+ return session;
+ }
+
+ ExecutionContext context() {
+ return context;
+ }
+
+ String workspaceName() {
+ return workspaceName;
+ }
+
+ JcrNodeTypeManager nodeTypes() {
+ return session.nodeTypeManager();
+ }
+
+ public JcrRootNode findJcrRootNode() throws RepositoryException {
+ return (JcrRootNode)findJcrNode(findNodeInfoForRoot().getUuid());
+ }
+
+ /**
+ * Find the JCR {@link JcrNode Node implementation} for the given UUID.
+ *
+ * @param uuid the node's UUID
+ * @return the existing node implementation
+ * @throws ItemNotFoundException if a node with the supplied UUID could not be found
+ * @throws RepositoryException if an error resulting in finding this node in the
repository
+ */
+ public AbstractJcrNode findJcrNode( UUID uuid ) throws ItemNotFoundException,
RepositoryException {
+ AbstractJcrNode node = jcrNodes.get(uuid);
+ if (node != null) return node;
+
+ // An existing JCR Node object was not found, so we'll have to create it by
finding the underlying
+ // NodeInfo for the node (from the changed state or the cache) ...
+ NodeInfo info = findNodeInfo(uuid);
+ assert info != null;
+
+ // Create the appropriate JCR Node object ...
+ return createAndCacheJcrNodeFor(info);
+ }
+
+ /**
+ * Find the JCR {@link AbstractJcrNode Node implementation} for the node given by the
UUID of a reference node and a relative
+ * path from the reference node. The relative path should already have been {@link
Path#getNormalizedPath() normalized}.
+ *
+ * @param uuidOfReferenceNode the UUID of the reference node; may be null if the root
node is to be used as the reference
+ * @param relativePath the relative (but normalized) path from the reference node,
but which may be an absolute (and
+ * normalized) path only when the reference node is the root node; may not be
null
+ * @return the information for the referenced node; never null
+ * @throws ItemNotFoundException if the reference node with the supplied UUID does
not exist
+ * @throws PathNotFoundException if the node given by the relative path does not
exist
+ * @throws RepositoryException if any other error occurs while reading information
from the repository
+ * @see #findNodeInfoForRoot()
+ */
+ public AbstractJcrNode findJcrNode( UUID uuidOfReferenceNode,
+ Path relativePath ) throws PathNotFoundException,
RepositoryException {
+ // An existing JCR Node object was not found, so we'll have to create it by
finding the underlying
+ // NodeInfo for the node (from the changed state or the cache) ...
+ NodeInfo info = findNodeInfo(uuidOfReferenceNode, relativePath);
+ assert info != null;
+
+ // Look for an existing node ...
+ AbstractJcrNode node = jcrNodes.get(info.getUuid());
+ if (node != null) return node;
+
+ // Create the appropriate JCR Node object ...
+ return createAndCacheJcrNodeFor(info);
+ }
+
+ public AbstractJcrProperty findJcrProperty( PropertyId propertyId ) throws
PathNotFoundException, RepositoryException {
+ AbstractJcrProperty property = jcrProperties.get(propertyId);
+ if (property != null) return property;
+
+ // An existing JCR Property object was not found, so we'll have to create it
by finding the underlying
+ // NodeInfo for the property's parent (from the changed state or the cache)
...
+ PropertyInfo info = findPropertyInfo(propertyId); // throws PathNotFoundException
if node not there
+ if (info == null) return null; // no such property on this node
+
+ // Now create the appropriate JCR Property object ...
+ return createAndCacheJcrPropertyFor(info);
+ }
+
+ public Collection<AbstractJcrProperty> findJcrPropertiesFor( UUID nodeUuid )
+ throws ItemNotFoundException, RepositoryException {
+ NodeInfo info = findNodeInfo(nodeUuid);
+ Map<Name, PropertyInfo> properties = info.getProperties();
+ Collection<AbstractJcrProperty> result = new
ArrayList<AbstractJcrProperty>(properties.size());
+ for (PropertyInfo propertyInfo : properties.values()) {
+ result.add(findJcrProperty(propertyInfo.getPropertyId()));
+ }
+ return result;
+ }
+
+ /**
+ * Find the JCR {@link AbstractJcrItem Item implementation} for the node or property
given by the UUID of a reference node and
+ * a relative path from the reference node to the desired item. The relative path
should already have been
+ * {@link Path#getNormalizedPath() normalized}.
+ *
+ * @param uuidOfReferenceNode the UUID of the reference node; may be null if the root
node is to be used as the reference
+ * @param relativePath the relative (but normalized) path from the reference node to
the desired item, but which may be an
+ * absolute (and normalized) path only when the reference node is the root
node; may not be null
+ * @return the information for the referenced item; never null
+ * @throws ItemNotFoundException if the reference node with the supplied UUID does
not exist, or if an item given by the
+ * supplied relative path does not exist
+ * @throws RepositoryException if any other error occurs while reading information
from the repository
+ * @see #findNodeInfoForRoot()
+ */
+ public AbstractJcrItem findJcrItem( UUID uuidOfReferenceNode,
+ Path relativePath ) throws ItemNotFoundException,
RepositoryException {
+ // A pathological case is an empty relative path ...
+ if (relativePath.size() == 0) {
+ return findJcrNode(uuidOfReferenceNode);
+ }
+ if (relativePath.size() == 1) {
+ Path.Segment segment = relativePath.getLastSegment();
+ if (segment.isSelfReference()) return findJcrNode(uuidOfReferenceNode);
+ if (segment.isParentReference()) {
+ NodeInfo referencedNode = findNodeInfo(uuidOfReferenceNode);
+ return findJcrNode(referencedNode.getParent());
+ }
+ }
+
+ // Peek into the last segment of the path to see whether it uses a SNS index (and
it's > 1) ...
+ Path.Segment lastSegment = relativePath.getLastSegment();
+ if (lastSegment.getIndex() > 1) {
+ // Only nodes can have SNS index (but an index of 1 is the default)...
+ return findJcrNode(uuidOfReferenceNode);
+ }
+
+ NodeInfo parent = null;
+ if (relativePath.size() == 1) {
+ // The referenced node must be the parent ...
+ parent = findNodeInfo(uuidOfReferenceNode);
+ } else {
+ // We know that the parent of the referenced item should be a node (if the
path is right) ...
+ parent = findNodeInfo(uuidOfReferenceNode, relativePath.getParent());
+ }
+
+ // JSR-170 doesn't allow children and proeprties to have the same name, but
this is relaxed in JSR-283.
+ // But JSR-283 Section 3.3.4 states "The method Session.getItem will return
the item at the specified path
+ // if there is only one such item, if there is both a node and a property at the
specified path, getItem
+ // will return the node." Therefore, look for a child first ...
+ ChildNode child = parent.getChildren().getChild(lastSegment);
+ if (child != null) {
+ return findJcrNode(child.getUuid());
+ }
+
+ // Otherwise it should be a property ...
+ PropertyInfo propertyInfo = parent.getProperty(lastSegment.getName());
+ if (propertyInfo != null) {
+ return findJcrProperty(propertyInfo.getPropertyId());
+ }
+
+ // It was not found, so prepare a good exception message ...
+ String msg = null;
+ if (findNodeInfoForRoot().getUuid().equals(uuidOfReferenceNode)) {
+ // The reference node was the root, so use this fact to convert the path to
an absolute path in the message
+ Path absolutePath = rootPath.resolve(relativePath);
+ msg = JcrI18n.itemNotFoundAtPath.text(absolutePath, workspaceName);
+ } else {
+ // Find the path of the reference node ...
+ Path referenceNodePath = getPathFor(uuidOfReferenceNode);
+ msg = JcrI18n.itemNotFoundAtPathRelativeToReferenceNode.text(relativePath,
referenceNodePath, workspaceName);
+ }
+ throw new ItemNotFoundException(msg);
+ }
+
+ /**
+ * Utility method that creates and caches the appropriate kind of AbstractJcrNode
implementation for node given by the
+ * supplied information.
+ *
+ * @param info the information for the node; may not be null
+ * @return the <i>new</i> instance of the {@link Node}; never null
+ */
+ private AbstractJcrNode createAndCacheJcrNodeFor( NodeInfo info ) {
+ UUID uuid = info.getUuid();
+ Location location = info.getOriginalLocation();
+ NodeDefinitionId nodeDefinitionId = info.getDefinitionId();
+ JcrNodeDefinition definition = nodeTypes().getNodeDefinition(nodeDefinitionId);
+ assert definition != null;
+
+ if (root == null) {
+ // Need to determine if this is the root node ...
+ if (location.getPath().isRoot()) {
+ // It is a root node ...
+ JcrRootNode node = new JcrRootNode(this, uuid);
+ jcrNodes.put(uuid, node);
+ root = uuid;
+ return node;
+ }
+ }
+
+ // It is not a root node ...
+ JcrNode node = new JcrNode(this, uuid);
+ jcrNodes.put(uuid, node);
+ return node;
+ }
+
+ /**
+ * Utility method that creates and caches the appropriate kind of AbstractJcrProperty
implementation for property given by the
+ * supplied information.
+ *
+ * @param info the information for the property; may not be null
+ * @return the <i>new</i> instance of the {@link Property}; never null
+ */
+ private AbstractJcrProperty createAndCacheJcrPropertyFor( PropertyInfo info ) {
+ boolean multiValued = info.getProperty().isMultiple();
+ JcrPropertyDefinition definition =
nodeTypes().getPropertyDefinition(info.getDefinitionId(), multiValued);
+ assert definition != null;
+ if (multiValued) {
+ return new JcrMultiValueProperty(this, info.getPropertyId());
+ }
+ return new JcrSingleValueProperty(this, info.getPropertyId());
+ }
+
+ // public AbstractJcrProperty findJcrProperty( Path propertyPath ) throws
PathNotFoundException, RepositoryException {
+ // if (propertyPath.isRoot()) return null;
+ // Path nodePath = propertyPath.getParent();
+ // NodeInfo nodeInfo = findNodeInfo(nodePath);
+ // Name propertyName = propertyPath.getLastSegment().getName();
+ // PropertyInfo info = nodeInfo.getProperty(propertyName);
+ //
+ // // Look for an existing JCR Property object ...
+ // PropertyId propertyId = info.getPropertyId();
+ // AbstractJcrProperty property = jcrProperties.get(propertyId);
+ // if (property != null) return property;
+ //
+ // // Now create the appropriate JCR Property object ...
+ // return createAndCacheJcrPropertyFor(info);
+ // }
+
+ /**
+ * Find the information for the node given by the UUID of the node. This is often the
fastest way to find information,
+ * especially after the information has been cached. Note, however, that this method
first checks the cache, and if the
+ * information is not in the cache, the information is read from the repository.
+ *
+ * @param uuid the UUID for the node; may not be null
+ * @return the information for the node with the supplied UUID, or null if the
information is not in the cache
+ * @throws ItemNotFoundException if there is no node with the supplied UUID
+ * @throws RepositoryException if any other error occurs while reading information
from the repository
+ * @see #findNodeInfoInCache(UUID)
+ * @see #findNodeInfo(UUID, Path)
+ * @see #findNodeInfoForRoot()
+ */
+ NodeInfo findNodeInfo( UUID uuid ) throws ItemNotFoundException, RepositoryException
{
+ // See if we already have something in the changed nodes ...
+ NodeInfo info = changedNodes.get(uuid);
+ if (info == null) {
+ // Or in the cache ...
+ info = cachedNodes.get(uuid);
+ if (info == null) {
+ info = loadFromGraph(uuid, null);
+ }
+ }
+ return info;
+ }
+
+ /**
+ * Find the information for the node given by the UUID of the node. This is often the
fastest way to find information,
+ * especially after the information has been cached. Note, however, that this method
only checks the cache.
+ *
+ * @param uuid the UUID for the node; may not be null
+ * @return the information for the node with the supplied UUID, or null if the
information is not in the cache
+ * @see #findNodeInfo(UUID)
+ * @see #findNodeInfo(UUID, Path)
+ * @see #findNodeInfoForRoot()
+ */
+ NodeInfo findNodeInfoInCache( UUID uuid ) {
+ // See if we already have something in the changed nodes ...
+ NodeInfo info = changedNodes.get(uuid);
+ if (info == null) {
+ // Or in the cache ...
+ info = cachedNodes.get(uuid);
+ }
+ return info;
+ }
+
+ /**
+ * Find the information for the root node. Generally, this returns information
that's in the cache, except for the first time
+ * the root node is needed.
+ *
+ * @return the node information
+ * @throws RepositoryException if there is an error while obtaining the information
from the repository
+ */
+ NodeInfo findNodeInfoForRoot() throws RepositoryException {
+ if (root == null) {
+ // We haven't found the root yet ...
+ NodeInfo info = loadFromGraph(this.rootPath, null);
+ root = info.getUuid();
+ this.jcrNodes.put(root, new JcrRootNode(this, root));
+ return info;
+ }
+ return findNodeInfo(root);
+ }
+
+ /**
+ * Find the information for the node given by the UUID of a reference node and a
relative path from the reference node.
+ *
+ * @param node the reference node; may be null if the root node is to be used as the
reference
+ * @param relativePath the relative path from the reference node, but which may be an
absolute path only when the reference
+ * node is the root node; may not be null
+ * @return the information for the referenced node; never null
+ * @throws ItemNotFoundException if the reference node with the supplied UUID does
not exist
+ * @throws PathNotFoundException if the node given by the relative path does not
exist
+ * @throws RepositoryException if any other error occurs while reading information
from the repository
+ * @see #findNodeInfoForRoot()
+ */
+ NodeInfo findNodeInfo( UUID node,
+ Path relativePath ) throws ItemNotFoundException,
PathNotFoundException, RepositoryException {
+ // The relative path must be normalized ...
+ assert relativePath.isNormalized();
+
+ // Find the node from which we're starting ...
+ NodeInfo fromInfo = null;
+ if (node == null) {
+ // This is only valid when the path is relative to the root (or it's an
absolute path)
+ fromInfo = findNodeInfoForRoot();
+ node = fromInfo.getUuid();
+ } else {
+ fromInfo = findNodeInfo(node);
+ assert relativePath.isAbsolute() ? node == root : true;
+ }
+ if (relativePath.isAbsolute()) {
+ relativePath = relativePath.relativeTo(this.rootPath);
+ }
+
+ // If the relative path is of zero-length ...
+ if (relativePath.size() == 0) {
+ return fromInfo;
+ }
+ // Or it is of length 1 but it is a self reference ...
+ if (relativePath.size() == 1 &&
relativePath.getLastSegment().isSelfReference()) {
+ return fromInfo;
+ }
+
+ // TODO: This could be more efficient than always walking the path. For example,
we could
+ // maintain a cache of paths. Right now, we are walking as much of the path as we
can,
+ // but as soon as we reach the bottom-most cached/changed node, we need to read
the rest
+ // from the graph. We are figuring out all of the remaining nodes and read them
from
+ // the graph in one batch operation, so that part is pretty good.
+
+ // Now, walk the path to find the nodes, being sure to look for changed
information ...
+ NodeInfo info = fromInfo;
+ Iterator<Path.Segment> pathsIter = relativePath.iterator();
+ while (pathsIter.hasNext()) {
+ Path.Segment child = pathsIter.next();
+ if (child.isParentReference()) {
+ // Walk up ...
+ UUID parentUuid = info.getParent();
+ if (parentUuid == null) {
+ assert info.getUuid() == findNodeInfoForRoot().getUuid();
+ String msg = JcrI18n.errorWhileFindingNodeWithPath.text(relativePath,
workspaceName);
+ throw new PathNotFoundException(msg);
+ }
+ info = findNodeInfo(parentUuid);
+ } else {
+ // Walk down ...
+ // Note that once we start walking down, a normalized path should never
have any more parent
+ // or self references
+ ChildNode childNodeInfo = info.getChildren().getChild(child);
+ if (childNodeInfo == null) {
+ // The node (no longer?) exists, so compute the
+ Path fromPath = getPathFor(fromInfo);
+ String msg = JcrI18n.pathNotFoundRelativeTo.text(relativePath,
fromPath, workspaceName);
+ throw new PathNotFoundException(msg);
+ }
+ // See if we already have something in the changed nodes ...
+ UUID uuid = childNodeInfo.getUuid();
+ NodeInfo childInfo = changedNodes.get(uuid);
+ if (childInfo == null) {
+ // Or in the cache ...
+ childInfo = cachedNodes.get(uuid);
+ if (childInfo == null) {
+ // At this point, we've reached the bottom of the nodes that
we have locally.
+ // Get the actual location of the last 'info', since all
paths will be relative to it...
+ Location actualLocation = info.getOriginalLocation();
+ Path actualPath = actualLocation.getPath();
+ Path nextPath = pathFactory.create(actualPath, child);
+ if (pathsIter.hasNext()) {
+ // There are multiple remaining paths, so load them all in
one batch operation,
+ // starting at the top-most path (the one we're currently
at)...
+ List<Path> pathsInBatch = new
LinkedList<Path>();
+ Results batchResults = null;
+ try {
+ Graph.Batch batch = store.batch();
+ batch.read(nextPath);
+ pathsInBatch.add(nextPath);
+ while (pathsIter.hasNext()) {
+ child = pathsIter.next();
+ nextPath = pathFactory.create(nextPath, child);
+ batch.read(nextPath);
+ pathsInBatch.add(nextPath);
+ }
+ batchResults = batch.execute();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException
e) {
+ Path fromPath = getPathFor(fromInfo);
+ throw new
PathNotFoundException(JcrI18n.pathNotFoundRelativeTo.text(relativePath,
+
fromPath,
+
workspaceName));
+ } catch (RepositorySourceException e) {
+ throw new
RepositoryException(JcrI18n.errorWhileFindingNodeWithUuid.text(uuid,
+
workspaceName,
+
e.getLocalizedMessage()));
+ }
+ // Now process all of the nodes that we loaded, again
starting at the top and going down ...
+ for (Path batchPath : pathsInBatch) {
+ org.jboss.dna.graph.Node dnaNode =
batchResults.getNode(batchPath);
+ childInfo = createNodeInfoFrom(dnaNode, info);
+ this.cachedNodes.put(childInfo.getUuid(), childInfo);
+ info = childInfo;
+ }
+ } else {
+ // This is the last path, so do it a little more efficiently
than above ...
+ childInfo = loadFromGraph(nextPath, info);
+ info = childInfo;
+ }
+ } else {
+ info = childInfo;
+ }
+ } else {
+ info = childInfo;
+ }
+ }
+ }
+ return info;
+ }
+
+ /**
+ * Find the property information with the given identifier. If the property is not
yet loaded into the cache, the node (and
+ * its properties) will be read from the repository.
+ *
+ * @param propertyId the identifier for the property; may not be null
+ * @return the property information, or null if the node does not contain the
specified property
+ * @throws PathNotFoundException if the node containing this property does not exist
+ * @throws RepositoryException if there is an error while obtaining the information
+ */
+ PropertyInfo findPropertyInfo( PropertyId propertyId ) throws PathNotFoundException,
RepositoryException {
+ NodeInfo info = findNodeInfo(propertyId.getNodeId());
+ return info.getProperty(propertyId.getPropertyName());
+ }
+
+ Path getPathFor( UUID uuid ) throws ItemNotFoundException, RepositoryException {
+ if (uuid == root) return rootPath;
+ return getPathFor(findNodeInfo(uuid));
+ }
+
+ Path getPathFor( NodeInfo info ) throws ItemNotFoundException, RepositoryException {
+ if (info != null && info.getUuid() == root) return rootPath;
+ LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
+ while (info != null) {
+ UUID parent = info.getParent();
+ if (parent == null) break;
+ NodeInfo parentInfo = findNodeInfo(parent);
+ ChildNode child = parentInfo.getChildren().getChild(info.getUuid());
+ if (child == null) break;
+ Path.Segment segment = pathFactory.createSegment(child.getName(),
child.getSnsIndex());
+
+ segments.addFirst(segment);
+ info = parentInfo;
+ }
+ return pathFactory.createAbsolutePath(segments);
+ }
+
+ Path getPathFor( PropertyInfo propertyInfo ) throws ItemNotFoundException,
RepositoryException {
+ Path nodePath = getPathFor(propertyInfo.getNodeUuid());
+ return pathFactory.create(nodePath, propertyInfo.getPropertyName());
+ }
+
+ Path getPathFor( PropertyId propertyId ) throws ItemNotFoundException,
RepositoryException {
+ return getPathFor(findPropertyInfo(propertyId));
+ }
+
+ protected Name getNameOf( UUID nodeUuid ) throws ItemNotFoundException,
RepositoryException {
+ findNodeInfoForRoot();
+ if (nodeUuid == root) return nameFactory.create("");
+ // Get the parent ...
+ NodeInfo info = findNodeInfo(nodeUuid);
+ NodeInfo parent = findNodeInfo(info.getParent());
+ ChildNode child = parent.getChildren().getChild(info.getUuid());
+ return child.getName();
+ }
+
+ protected int getSnsIndexOf( UUID nodeUuid ) throws ItemNotFoundException,
RepositoryException {
+ findNodeInfoForRoot();
+ if (nodeUuid == root) return 1;
+ // Get the parent ...
+ NodeInfo info = findNodeInfo(nodeUuid);
+ NodeInfo parent = findNodeInfo(info.getParent());
+ ChildNode child = parent.getChildren().getChild(info.getUuid());
+ return child.getSnsIndex();
+ }
+
+ /**
+ * Load from the underlying repository graph the information for the node with the
supplied UUID. This method returns the
+ * information for the requested node (after placing it in the cache), but this
method may (at its discretion) also load and
+ * cache information for other nodes.
+ * <p>
+ * Note that this method does not check the cache before loading from the repository
graph.
+ * </p>
+ *
+ * @param uuid the UUID of the node; may not be null
+ * @param parentInfo the parent information; may be null if not known
+ * @return the information for the node
+ * @throws ItemNotFoundException if the node does not exist in the repository
+ * @throws RepositoryException if there was an error obtaining this information from
the repository
+ */
+ protected NodeInfo loadFromGraph( UUID uuid,
+ NodeInfo parentInfo ) throws ItemNotFoundException,
RepositoryException {
+ // Load the node information from the store ...
+ try {
+ org.jboss.dna.graph.Node node = store.getNodeAt(uuid);
+ NodeInfo info = createNodeInfoFrom(node, parentInfo);
+ this.cachedNodes.put(info.getUuid(), info);
+ return info;
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new ItemNotFoundException(JcrI18n.itemNotFoundWithUuid.text(uuid,
workspaceName, e.getLocalizedMessage()));
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(
+
JcrI18n.errorWhileFindingNodeWithUuid.text(uuid, workspaceName,
e.getLocalizedMessage()));
+ }
+ }
+
+ /**
+ * Load from the underlying repository graph the information for the node with the
supplied UUID. This method returns the
+ * information for the requested node (after placing it in the cache), but this
method may (at its discretion) also load and
+ * cache information for other nodes.
+ * <p>
+ * Note that this method does not check the cache before loading from the repository
graph.
+ * </p>
+ *
+ * @param path the path to the node; may not be null
+ * @param parentInfo the parent information; may be null if not known
+ * @return the information for the node
+ * @throws PathNotFoundException if the node does not exist in the repository
+ * @throws RepositoryException if there was an error obtaining this information from
the repository
+ */
+ protected NodeInfo loadFromGraph( Path path,
+ NodeInfo parentInfo ) throws PathNotFoundException,
RepositoryException {
+ // Load the node information from the store ...
+ try {
+ org.jboss.dna.graph.Node node = store.getNodeAt(path);
+ NodeInfo info = createNodeInfoFrom(node, parentInfo);
+ this.cachedNodes.put(info.getUuid(), info);
+ return info;
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new PathNotFoundException(JcrI18n.pathNotFound.text(path,
workspaceName));
+ } catch (RepositorySourceException e) {
+ throw new
RepositoryException(JcrI18n.errorWhileFindingNodeWithPath.text(path, workspaceName));
+ }
+ }
+
+ /**
+ * Create the {@link NodeInfo} object given the DNA graph node and the parent node
information (if it is available).
+ *
+ * @param graphNode the DNA graph node; may not be null
+ * @param parentInfo the information for the parent node, or null if the supplied
graph node represents the root node, or if
+ * the parent information is not known
+ * @return the node information; never null
+ * @throws RepositoryException if there is an error determining the child {@link
NodeDefinition} for the supplied node,
+ * preventing the node information from being constructed
+ */
+ private NodeInfo createNodeInfoFrom( org.jboss.dna.graph.Node graphNode,
+ NodeInfo parentInfo ) throws RepositoryException
{
+ // Now get the DNA node's UUID and find the DNA property containing the UUID
...
+ Location location = graphNode.getLocation();
+ ValueFactories factories = context.getValueFactories();
+ UUID uuid = location.getUuid();
+ org.jboss.dna.graph.property.Property uuidProperty = null;
+ if (uuid != null) {
+ // Check for 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 = propertyFactory.create(JcrLexicon.UUID,
uuid);
+
+ // 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 ...
+ Map<Name, Property> graphProperties = graphNode.getPropertiesByName();
+ final boolean isRoot = location.getPath().isRoot();
+ Name primaryTypeName = null;
+ org.jboss.dna.graph.property.Property primaryTypeProperty =
graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
+ if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
+ try {
+ primaryTypeName =
factories.getNameFactory().create(primaryTypeProperty.getFirstValue());
+ } catch (ValueFormatException e) {
+ // use the default ...
+ }
+ }
+ if (primaryTypeName == null) {
+ // We have to have a primary type, so use the default ...
+ if (isRoot) {
+ primaryTypeName = DnaLexicon.ROOT;
+ primaryTypeProperty = propertyFactory.create(JcrLexicon.PRIMARY_TYPE,
primaryTypeName);
+ } else {
+ primaryTypeName = defaultPrimaryTypeName;
+ primaryTypeProperty = defaultPrimaryTypeProperty;
+ }
+ // We have to add this property to the graph node...
+ graphProperties = new HashMap<Name, Property>(graphProperties);
+ graphProperties.put(primaryTypeProperty.getName(), primaryTypeProperty);
+ }
+ assert primaryTypeProperty != null;
+ assert primaryTypeProperty.isEmpty() == false;
+
+ // Look for a node definition stored on the node ...
+ JcrNodeDefinition definition = null;
+ org.jboss.dna.graph.property.Property nodeDefnProperty =
graphProperties.get(DnaLexicon.NODE_DEFINITON);
+ if (nodeDefnProperty != null && !nodeDefnProperty.isEmpty()) {
+ String nodeDefinitionString =
stringFactory.create(nodeDefnProperty.getFirstValue());
+ NodeDefinitionId id = NodeDefinitionId.fromString(nodeDefinitionString,
nameFactory);
+ definition = nodeTypes().getNodeDefinition(id);
+ }
+ // Figure out the node definition for this node ...
+ if (definition == null) {
+ if (isRoot) {
+ definition = nodeTypes().getRootNodeDefinition();
+ } else {
+ // We need the parent ...
+ Path path = location.getPath();
+ if (parentInfo == null) {
+ Path parentPath = path.getParent();
+ parentInfo = findNodeInfo(null, parentPath.getNormalizedPath());
+ }
+ Name childName = path.getLastSegment().getName();
+ definition = findNodeDefinitionForChild(parentInfo, childName,
primaryTypeName);
+ if (definition == null) {
+ String msg =
JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(path, workspaceName);
+ throw new RepositorySourceException(msg);
+ }
+ }
+ }
+
+ // Create the node information ...
+ NodeInfo info = new NodeInfo(location, primaryTypeName, definition.getId());
+ if (parentInfo != null) {
+ info.setParent(parentInfo.getUuid());
+ }
+
+ // --------------------------------------------------
+ // Set the node's children ...
+ // --------------------------------------------------
+ info.setChildren(graphNode.getChildren());
+
+ // ------------------------------------------------------
+ // Set the node's properties ...
+ // ------------------------------------------------------
+ // First get the property type for each property, based upon the primary type and
mixins ...
+ // The map with single-valued properties...
+ Map<Name, PropertyDefinition> svPropertyDefinitionsByPropertyName = new
HashMap<Name, PropertyDefinition>();
+ // ... and the map with multi-valued properties
+ Map<Name, PropertyDefinition> mvPropertyDefinitionsByPropertyName = new
HashMap<Name, PropertyDefinition>();
+
+ boolean referenceable = false;
+
+ List<PropertyDefinition> anyPropertyDefinitions = new
LinkedList<PropertyDefinition>();
+ // Start with the primary type ...
+ NodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
+ for (PropertyDefinition propertyDefn : primaryType.getPropertyDefinitions()) {
+ String nameString = propertyDefn.getName();
+ if ("*".equals(nameString)) {
+ anyPropertyDefinitions.add(propertyDefn);
+ continue;
+ }
+ Name name = nameFactory.create(nameString);
+
+ if (propertyDefn.isMultiple()) {
+ PropertyDefinition prev = mvPropertyDefinitionsByPropertyName.put(name,
propertyDefn);
+ if (prev != null) mvPropertyDefinitionsByPropertyName.put(name, prev); //
put the first one back ...
+ } else {
+ PropertyDefinition prev = svPropertyDefinitionsByPropertyName.put(name,
propertyDefn);
+ if (prev != null) svPropertyDefinitionsByPropertyName.put(name, prev); //
put the first one back ...
+ }
+ }
+ // The process the mixin types ...
+ org.jboss.dna.graph.property.Property mixinTypesProperty =
graphProperties.get(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(namespaces);
+ NodeType mixinType = nodeTypes().getNodeType(mixinTypeNameString);
+ for (PropertyDefinition propertyDefn :
mixinType.getPropertyDefinitions()) {
+ String nameString = propertyDefn.getName();
+ if ("*".equals(nameString)) {
+ anyPropertyDefinitions.add(propertyDefn);
+ continue;
+ }
+ Name name = nameFactory.create(nameString);
+ if (propertyDefn.isMultiple()) {
+ PropertyDefinition prev =
mvPropertyDefinitionsByPropertyName.put(name, propertyDefn);
+ if (prev != null) mvPropertyDefinitionsByPropertyName.put(name,
prev); // put the first one back ...
+ } else {
+ PropertyDefinition prev =
svPropertyDefinitionsByPropertyName.put(name, propertyDefn);
+ if (prev != null) svPropertyDefinitionsByPropertyName.put(name,
prev); // put the first one back ...
+ }
+ }
+ }
+ }
+
+ // Now create the JCR property object wrappers around the other properties ...
+ for (org.jboss.dna.graph.property.Property dnaProp : graphProperties.values()) {
+ Name name = dnaProp.getName();
+
+ // Figure out the JCR property type for this property ...
+ PropertyDefinition propertyDefinition;
+ if (dnaProp.isMultiple()) {
+ propertyDefinition = mvPropertyDefinitionsByPropertyName.get(name);
+ } else {
+ propertyDefinition = svPropertyDefinitionsByPropertyName.get(name);
+
+ // If the property has only one value, dnaProp.isMultiple() will return
false, but the
+ // property may actually be a multi-valued property that happens to have
one property set.
+ if (propertyDefinition == null) {
+ propertyDefinition = mvPropertyDefinitionsByPropertyName.get(name);
+ }
+ }
+
+ // If no property type was found for this property, see if there is a
wildcard property ...
+ if (propertyDefinition == null) {
+ for (Iterator<PropertyDefinition> iter =
anyPropertyDefinitions.iterator(); iter.hasNext();) {
+ PropertyDefinition nextDef = iter.next();
+
+ // Grab the first residual definition that matches on cardinality
(single-valued vs. multi-valued)
+ if ((nextDef.isMultiple() && dnaProp.isMultiple()) ||
(!nextDef.isMultiple() && !dnaProp.isMultiple())) {
+ propertyDefinition = nextDef;
+ break;
+ }
+ }
+ }
+
+ // If there still is no property type defined ...
+ if (propertyDefinition == null) {
+ assert anyPropertyDefinitions.isEmpty();
+ if (INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS) {
+ // We can use the "nt:unstructured" property definitions
for any property ...
+ NodeType unstructured =
nodeTypes().getNodeType(JcrNtLexicon.UNSTRUCTURED);
+ for (PropertyDefinition anyDefinition :
unstructured.getDeclaredPropertyDefinitions()) {
+ if (anyDefinition.isMultiple()) {
+ propertyDefinition = anyDefinition;
+ break;
+ }
+ }
+ }
+ }
+ if (propertyDefinition == null) {
+ // We're supposed to skip this property (since we don't have a
definition for it) ...
+ continue;
+ }
+
+ // Figure out if this is a multi-valued property ...
+ boolean isMultiple = propertyDefinition.isMultiple();
+ if (!isMultiple && dnaProp.isEmpty()) {
+ // Only multi-valued properties can have no values; so if not
multi-valued, then skip ...
+ continue;
+ }
+
+ // Figure out the property type ...
+ int propertyType = propertyDefinition.getRequiredType();
+ if (propertyType == PropertyType.UNDEFINED) {
+ propertyType = JcrSession.jcrPropertyTypeFor(dnaProp);
+ }
+
+ // Record the property in the node information ...
+ PropertyId propId = new PropertyId(uuid, name);
+ info.setProperty(propId, (JcrPropertyDefinition)propertyDefinition,
propertyType, dnaProp);
+ }
+
+ // Now add the "jcr:uuid" property if and only if referenceable ...
+ if (referenceable) {
+ // We know that this property is single-valued
+ PropertyDefinition propertyDefinition =
svPropertyDefinitionsByPropertyName.get(JcrLexicon.UUID);
+ PropertyId propId = new PropertyId(uuid, JcrLexicon.UUID);
+ info.setProperty(propId, (JcrPropertyDefinition)propertyDefinition,
PropertyType.STRING, uuidProperty);
+ } else {
+ // Make sure there is NOT a "jcr:uuid" property ...
+ info.removeProperty(JcrLexicon.UUID);
+ }
+ // Make sure the "dna:uuid" property did not get in there ...
+ info.removeProperty(DnaLexicon.UUID);
+
+ return info;
+ }
+
+ /**
+ * Utility method to find the {@link NodeDefinition} for a child node with the
supplied {@link Name name}, parent information,
+ * and the primary node type of the child.
+ *
+ * @param parentInfo the parent information; may not be null
+ * @param childName the name of the child node (without any same-name-sibling index);
may not be null
+ * @param primaryTypeOfChild the name of the child's primary type
+ * @return the node definition for this child, as best as can be determined, or null
if the node definition could not be
+ * determined
+ * @throws RepositoryException if the parent's pimary node type cannot be found
in the {@link NodeTypeManager}
+ */
+ protected JcrNodeDefinition findNodeDefinitionForChild( NodeInfo parentInfo,
+ Name childName,
+ Name primaryTypeOfChild )
throws RepositoryException {
+ // Get the primary type of the parent, and look at it's child definitions
...
+ Name primaryTypeName = parentInfo.getPrimaryTypeName();
+ JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
+ if (primaryType == null) {
+ String msg = JcrI18n.missingNodeTypeForExistingNode.text(primaryTypeName,
parentInfo.getUuid(), workspaceName);
+ throw new RepositoryException(msg);
+ }
+ // TODO: should this also check the mixins?
+ return primaryType.findBestNodeDefinitionForChild(childName,
primaryTypeOfChild);
+ }
+
+ /**
+ * The information that describes a node. This is the information that is kept in the
{@link SessionCache#cachedNodes cache}
+ * and in the record of {@link SessionCache#changedNodes changes} made by the session
but not yet commited/saved.
+ */
+ @NotThreadSafe
+ protected class NodeInfo {
+ private final Location originalLocation;
+ private final UUID uuid;
+ private UUID parent;
+ private final Name primaryTypeName;
+ private final NodeDefinitionId definition;
+ private final Children children;
+ private final Map<Name, PropertyInfo> properties;
+
+ protected NodeInfo( Location originalLocation,
+ Name primaryTypeName,
+ NodeDefinitionId definition ) {
+ this.originalLocation = originalLocation;
+ this.primaryTypeName = primaryTypeName;
+ this.definition = definition;
+ this.uuid = this.originalLocation.getUuid();
+ this.children = new Children(this.uuid);
+ this.properties = new HashMap<Name, PropertyInfo>();
+ assert this.uuid != null;
+ assert this.definition != null;
+ assert this.primaryTypeName != null;
+ }
+
+ /**
+ * @return location
+ */
+ public Location getOriginalLocation() {
+ return originalLocation;
+ }
+
+ /**
+ * @return uuid
+ */
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ /**
+ * @return parent
+ */
+ public UUID getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent Sets parent to the specified value.
+ */
+ protected void setParent( UUID parent ) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return primaryTypeName
+ */
+ public Name getPrimaryTypeName() {
+ return primaryTypeName;
+ }
+
+ /**
+ * @return definition
+ */
+ public NodeDefinitionId getDefinitionId() {
+ return definition;
+ }
+
+ /**
+ * Get the children for this node.
+ *
+ * @return the children; never null but possibly empty
+ */
+ public Children getChildren() {
+ return children;
+ }
+
+ /**
+ * @param children Sets children to the specified value.
+ * @return the children information; never null
+ */
+ public Children setChildren( List<Location> children ) {
+ this.children.append(SessionCache.this, children, true);
+ return this.children;
+ }
+
+ /**
+ * Get the map of information for each property.
+ *
+ * @return the information for each property; never null but possibly (though
unlikely) empty
+ */
+ public Map<Name, PropertyInfo> getProperties() {
+ return this.properties; // never null
+ }
+
+ public PropertyInfo getProperty( Name name ) {
+ return this.properties.get(name);
+ }
+
+ public PropertyInfo setProperty( PropertyId id,
+ JcrPropertyDefinition definition,
+ int propertyType,
+ Property dnaProperty ) {
+ // Initialize the map if required (this never replaces it, though) ...
+ PropertyInfo info = new PropertyInfo(id, definition.getId(), propertyType,
dnaProperty, definition.isMultiple());
+ return this.properties.put(id.getPropertyName(), info);
+ }
+
+ public PropertyInfo removeProperty( Name name ) {
+ return this.properties.remove(name);
+ }
+ }
+
+ /**
+ * An immutable representation of the name and current value(s) for a property, along
with the JCR metadata for the property,
+ * including the {@link PropertyInfo#getDefinitionId() property definition} and
{@link PropertyInfo#getPropertyType() property
+ * type}.
+ * <p>
+ * This class is immutable, which means that clients should never hold onto an
instance. Instead, clients can obtain an
+ * instance by using a {@link PropertyId}, quickly use the information in the
instance, and then immediately discard their
+ * reference. This is because these instances are replaced and discarded whenever
anything about the property changes.
+ * </p>
+ */
+ @Immutable
+ public static class PropertyInfo {
+ private final PropertyId propertyId;
+ private final PropertyDefinitionId definitionId;
+ private final Property dnaProperty;
+ private final int propertyType;
+ private final boolean multiValued;
+
+ protected PropertyInfo( PropertyId propertyId,
+ PropertyDefinitionId definitionId,
+ int propertyType,
+ Property dnaProperty,
+ boolean multiValued ) {
+ this.propertyId = propertyId;
+ this.definitionId = definitionId;
+ this.propertyType = propertyType;
+ this.dnaProperty = dnaProperty;
+ this.multiValued = multiValued;
+ }
+
+ /**
+ * Get the durable identifier for this property.
+ *
+ * @return propertyId
+ */
+ public PropertyId getPropertyId() {
+ return propertyId;
+ }
+
+ /**
+ * Get the UUID of the node to which this property belongs.
+ *
+ * @return the owner node's UUID; never null
+ */
+ public UUID getNodeUuid() {
+ return propertyId.getNodeId();
+ }
+
+ /**
+ * The identifier for the property definition.
+ *
+ * @return the property definition ID; never null
+ */
+ public PropertyDefinitionId getDefinitionId() {
+ return definitionId;
+ }
+
+ /**
+ * Get the DNA Property, which contains the name and value(s)
+ *
+ * @return the property; never null
+ */
+ public Property getProperty() {
+ return dnaProperty;
+ }
+
+ /**
+ * Get the property name.
+ *
+ * @return the property name; never null
+ */
+ public Name getPropertyName() {
+ return dnaProperty.getName();
+ }
+
+ /**
+ * Get the JCR {@link PropertyType} for this property.
+ *
+ * @return the property type
+ */
+ public int getPropertyType() {
+ return propertyType;
+ }
+
+ /**
+ * @return multiValued
+ */
+ public boolean isMultiValued() {
+ return multiValued;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return propertyId.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyInfo) {
+ return propertyId.equals(((PropertyInfo)obj).getPropertyId());
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(propertyId);
+ sb.append(" defined by ").append(definitionId);
+ sb.append(" of type
").append(PropertyType.nameFromValue(propertyType));
+ if (dnaProperty.isSingle()) {
+ sb.append(" with value ");
+ } else {
+ sb.append(" with values ");
+ }
+ sb.append(dnaProperty.getValuesAsArray());
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Class that maintains the ordered list of {@link ChildNode} instances. This class
uses a {@link ListMultimap} to maintain
+ * insertion order of the child nodes, and to allow fast access to the children with
a specified name.
+ */
+ @ThreadSafe
+ public final static class Children implements Iterable<ChildNode> {
+ private final UUID parentUuid;
+ private final Map<UUID, ChildNode> childrenByUuid;
+ private final ListMultimap<Name, ChildNode> childrenByName;
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ Children( UUID parentUuid ) {
+ this.parentUuid = parentUuid;
+ this.childrenByUuid = new HashMap<UUID, ChildNode>();
+ this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
+ }
+
+ /**
+ * Get the number of children.
+ *
+ * @return the number of children
+ */
+ public int size() {
+ try {
+ lock.readLock().lock();
+ return childrenByName.size();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the children.
+ *
+ * @return a copy of the list of children
+ */
+ public List<ChildNode> asList() {
+ try {
+ lock.readLock().lock();
+ return new ArrayList<ChildNode>(childrenByName.values());
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the children.
+ *
+ * @return a copy of the list of children
+ */
+ public Iterator<ChildNode> iterator() {
+ return asList().iterator();
+ }
+
+ /**
+ * The UUID of the parent node.
+ *
+ * @return the parent node's UUID
+ */
+ public UUID getParentUuid() {
+ return parentUuid;
+ }
+
+ /**
+ * Get the child with the given UUID.
+ *
+ * @param uuid the UUID of the child node
+ * @return the child node, or null if there is no child with the supplied UUID
+ */
+ public ChildNode getChild( UUID uuid ) {
+ try {
+ lock.readLock().lock();
+ return this.childrenByUuid.get(uuid);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the child given the path segment.
+ *
+ * @param segment the path segment for the child, which includes the {@link
Path.Segment#getName() name} and
+ * {@link Path.Segment#getIndex() one-based same-name-sibling index}; may
not be null
+ * @return the information for the child node, or null if no such child existed
+ */
+ public ChildNode getChild( Path.Segment segment ) {
+ try {
+ lock.readLock().lock();
+ List<ChildNode> childrenWithName =
this.childrenByName.get(segment.getName());
+ int snsIndex = segment.getIndex();
+ if (childrenWithName.size() < snsIndex) return null;
+ return childrenWithName.get(snsIndex - 1);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the same-name-sibling children that all share the supplied name.
+ *
+ * @param name the name for the children; may not be null
+ * @return the children with the supplied name; never null
+ */
+ public List<ChildNode> getChildren( Name name ) {
+ try {
+ lock.readLock().lock();
+ return new ArrayList<ChildNode>(this.childrenByName.get(name));
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Remove the child with the given path segment.
+ *
+ * @param segment the path segment for the child, which includes the {@link
Path.Segment#getName() name} and
+ * {@link Path.Segment#getIndex() one-based same-name-sibling index}; may
not be null
+ * @return the information for the child node that was removed, or null if no
such child existed
+ */
+ public ChildNode remove( Path.Segment segment ) {
+ try {
+ lock.writeLock().lock();
+ List<ChildNode> childrenWithName =
this.childrenByName.get(segment.getName());
+ int snsIndex = segment.getIndex();
+ int numChildrenWithName = childrenWithName.size();
+ if (numChildrenWithName < snsIndex) return null;
+ ChildNode result = childrenWithName.remove(snsIndex);
+ this.childrenByUuid.remove(result.getUuid());
+ --numChildrenWithName;
+ if (numChildrenWithName > snsIndex) {
+ // We need to reduce the SNS index of every child after the one that
was just removed ...
+ ListIterator<ChildNode> siblingIter =
childrenWithName.listIterator(snsIndex);
+ while (siblingIter.hasNext()) {
+ // Remove the next child and replace with one having the correct
SNS index ...
+ ChildNode next = siblingIter.next();
+ siblingIter.remove();
+ siblingIter.set(next.withChangedSnsIndex(-1));
+ }
+ }
+ return result;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Add a new child to the end of the list of existing children a new child with
the supplied name and UUID. The
+ * same-name-sibling will be determined to be one more than the number of
existing children with the same name.
+ *
+ * @param cache the cache; may not be null
+ * @param name the name for the child to be appended; may not be null
+ * @param childUuid the UUID of the child; may not be null
+ * @return the information for the newly-added child; never null
+ */
+ public ChildNode append( SessionCache cache,
+ Name name,
+ UUID childUuid ) {
+ try {
+ lock.writeLock().lock();
+ List<ChildNode> childrenWithName = this.childrenByName.get(name);
+ ChildNode child = new ChildNode(childUuid, name, childrenWithName.size()
+ 1);
+ childrenWithName.add(child);
+ this.childrenByUuid.put(childUuid, child);
+ // Look for the child in the cache/changed nodes ...
+ NodeInfo childInfo = cache.findNodeInfoInCache(childUuid);
+ if (childInfo != null) childInfo.setParent(parentUuid);
+ return child;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Append the children described by the supplied Location objects, optionally
removing all existing children first.
+ *
+ * @param cache the cache; may not be null
+ * @param children a list containing a Location object for each child
+ * @param removeExistingFirst true if the existing children should be removed
before these children are added, or false if
+ * these children should be appended to the existing children
+ */
+ public void append( SessionCache cache,
+ List<Location> children,
+ boolean removeExistingFirst ) {
+ try {
+ lock.writeLock().lock();
+ if (removeExistingFirst && !this.childrenByName.isEmpty()) {
+ for (ChildNode child : this.childrenByName.values()) {
+ // Look for the child in the cache/changed nodes ...
+ NodeInfo childInfo = cache.findNodeInfoInCache(child.getUuid());
+ if (childInfo != null) childInfo.setParent(null);
+ // TODO: These nodes are deleted and should be handled as deletes
...
+ }
+ this.childrenByUuid.clear();
+ this.childrenByName.clear();
+ }
+ for (Location childLocation : children) {
+ UUID childUuid = childLocation.getUuid();
+ Path.Segment segment = childLocation.getPath().getLastSegment();
+ Name name = segment.getName();
+ ChildNode child = new ChildNode(childUuid, name,
segment.getIndex());
+ this.childrenByName.put(name, child);
+ this.childrenByUuid.put(childUuid, child);
+ // Look for the child in the cache/changed nodes ...
+ NodeInfo childInfo = cache.findNodeInfoInCache(childUuid);
+ if (childInfo != null) childInfo.setParent(parentUuid);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ try {
+ lock.readLock().lock();
+ boolean first = true;
+ for (ChildNode child : childrenByName.values()) {
+ if (!first) sb.append(", ");
+ else first = false;
+
sb.append(child.getName()).append('[').append(child.getSnsIndex()).append(']');
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * The information about a child node. This is designed to be found in the {@link
Children}, used quickly, and discarded.
+ * Clients should not hold on to these objects, since any changes to the children
involve discarding the old ChildNode objects
+ * and replacing them with new instances.
+ */
+ @Immutable
+ public final static class ChildNode {
+ private final UUID uuid;
+ private final Name name;
+ private final int snsIndex;
+
+ protected ChildNode( UUID uuid,
+ Name name,
+ int snsIndex ) {
+ this.uuid = uuid;
+ this.name = name;
+ this.snsIndex = snsIndex;
+ assert this.snsIndex > 0;
+ }
+
+ /**
+ * Get the UUID of the node.
+ *
+ * @return the node's UUID; never null
+ */
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ /**
+ * Get the name of the node.
+ *
+ * @return the node's current name; never null
+ */
+ public Name getName() {
+ return name;
+ }
+
+ /**
+ * Get the same-name-sibling index of the node.
+ *
+ * @return the node's SNS index; always positive
+ */
+ public int getSnsIndex() {
+ return snsIndex;
+ }
+
+ /**
+ * Return a new child node that has a changed SNS index.
+ *
+ * @param delta the amount the change the SNS index, either positive to increase
the value or negative to decrease the
+ * value
+ * @return the copy of this, with a changed SNS index; never null
+ */
+ public ChildNode withChangedSnsIndex( int delta ) {
+ return new ChildNode(uuid, name, snsIndex + delta);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof ChildNode) {
+ return this.uuid.equals(((ChildNode)obj).uuid);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return uuid.toString() + " ( " + name + "[" + snsIndex +
"] )";
+ }
+ }
+
+}
Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
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-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-03-16
22:50:09 UTC (rev 777)
@@ -28,7 +28,8 @@
defaultWorkspaceName=
inputStreamConsumed = This value was already consumed as an input stream.
nonInputStreamConsumed = This value was already consumed as a non-input stream.
-pathNotFound = No item exists at path {0}
+pathNotFound = No item exists at path {0} in workspace "{1}"
+pathNotFoundRelativeTo = No item exists at path {0} relative to {1} in workspace
"{2}"
permissionDenied = Permission denied to perform actions "{1}" on path {0}.
repositoryMustBeConfigured = DNA repositories must be configured with either a repository
source factory or a repository source.
sourceInUse = All sessions must end before a new repository source can be set.
@@ -51,9 +52,19 @@
invalidRelativePath = "{0}" is not a valid relative path
invalidPathParameter = The "{1}" parameter value "{0}" was not a
valid path
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}"
+noPrimaryItemNameDefinedOnPrimaryType = The primary type "{0}" for node
"{1}" in workspace "{2}" does not define a primary item name
+primaryItemNameForPrimaryTypeIsNotValid = The primary type "{0}" for node
"{2}" in workspace "{3}" defines an invalid primary item name
("{1}")
+primaryItemDoesNotExist = The node "{2}" in workspace "{3}" does not
have an item named "{1}" as defined by its primary type "{0}"
+itemNotFoundWithUuid = An item with UUID "{0}" could not be found in workspace
"{1}": {2}
+itemNotFoundAtPath = An item at "{0}" could not be found in workspace
"{1}"
+itemNotFoundAtPathRelativeToReferenceNode = An item at "{0}" relative to
"{1}" could not be found in workspace "{2}"
+propertyNotFoundAtPathRelativeToReferenceNode = A property at "{0}" relative to
"{1}" could not be found in workspace "{2}"
+nodeNotFoundAtPathRelativeToReferenceNode = A node at "{0}" relative to
"{1}" could not be found in workspace "{2}"
+childNotFoundUnderNode = The child "{0}" could not be found under
"{1}" in workspace "{2}"
+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}"
+missingNodeTypeForExistingNode = Missing primary node type "{0}" for node {1}
in workspace "{2}"
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/AbstractJcrItemTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrItemTest.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrItemTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -27,24 +27,36 @@
import static org.junit.Assert.assertThat;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
-import javax.jcr.Session;
+import org.jboss.dna.graph.property.Path;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
-/**
- * @author jverhaeg
- */
public class AbstractJcrItemTest {
private AbstractJcrItem item;
+ @Mock
+ private SessionCache cache;
@Before
public void before() {
- item = new AbstractJcrItem() {
+ MockitoAnnotations.initMocks(this);
+ item = new AbstractJcrItem(cache) {
public void accept( ItemVisitor visitor ) {
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.AbstractJcrItem#path()
+ */
+ @Override
+ Path path() {
+ throw new UnsupportedOperationException();
+ }
+
public String getName() {
return null;
}
@@ -57,10 +69,6 @@
return null;
}
- public Session getSession() {
- return null;
- }
-
public boolean isNode() {
return false;
}
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-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -25,13 +25,13 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
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;
+import java.util.Arrays;
import java.util.Calendar;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -39,20 +39,23 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
+import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
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.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.jcr.SessionCache.Children;
+import org.jboss.dna.jcr.SessionCache.NodeInfo;
+import org.jboss.dna.jcr.SessionCache.PropertyInfo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
@@ -64,36 +67,16 @@
*/
public class AbstractJcrNodeTest {
- static MockAbstractJcrNode createChild( JcrSession session,
- String name,
- int index,
- List<Location> children,
- AbstractJcrNode parent ) throws Exception {
- MockAbstractJcrNode child = new MockAbstractJcrNode(session, name, parent);
- String parentPath = parent.getPath();
- String childPath = parentPath + "/" + name + "[" + index +
"]";
- Path path =
session.getExecutionContext().getValueFactories().getPathFactory().create(childPath);
- Location location = Location.create(path, UUID.randomUUID());
- children.add(location);
- // Stub the session to return this node ...
- String absolutePath =
path.getString(session.getExecutionContext().getNamespaceRegistry());
- stub(session.getChild(parent, location)).toReturn(child);
- stub(session.getNode(location.getUuid())).toReturn(child);
- stub(session.getItem(absolutePath)).toReturn(child);
- return child;
- }
-
static class MockAbstractJcrNode extends AbstractJcrNode {
- String name;
- Node parent;
+ MockAbstractJcrNode( SessionCache cache,
+ UUID uuid ) {
+ super(cache, uuid);
+ }
- MockAbstractJcrNode( JcrSession session,
- String name,
- Node parent ) {
- super(session, Location.create(UUID.randomUUID()),
mock(NodeDefinition.class));
- this.name = name;
- this.parent = parent;
+ @Override
+ boolean isRoot() {
+ return false;
}
@Override
@@ -105,45 +88,67 @@
return 0;
}
- public String getName() {
- return name;
+ public String getName() throws RepositoryException {
+ return
cache.getPathFor(nodeInfo()).getLastSegment().getString(namespaces());
}
- public Node getParent() {
- return parent;
+ public Node getParent() throws RepositoryException {
+ return cache.findJcrNode(nodeInfo().getParent());
}
public String getPath() throws RepositoryException {
- return (parent == null ? '/' + getName() : parent.getPath() +
'/' + getName());
+ return cache.getPathFor(nodeInfo()).getString(namespaces());
}
}
+ private ExecutionContext context;
+ private UUID uuid;
private AbstractJcrNode node;
+ private Children children;
@Mock
+ private SessionCache cache;
+ @Mock
private JcrSession session;
@Mock
- private Workspace workspace;
+ private JcrNodeTypeManager nodeTypes;
@Mock
- private Repository repository;
- private List<Location> children;
- private Map<Name, Property> properties;
- private ExecutionContext context;
+ private NodeInfo info;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
context = new ExecutionContext();
- stub(session.getExecutionContext()).toReturn(context);
- children = new ArrayList<Location>();
- properties = new HashMap<Name, Property>();
- node = new MockAbstractJcrNode(session, "node", null);
- node.setProperties(properties);
+ context.getNamespaceRegistry().register("acme",
"http://www.example.com");
+ uuid = UUID.randomUUID();
+ stub(cache.session()).toReturn(session);
+ stub(cache.context()).toReturn(context);
+ stub(cache.workspaceName()).toReturn("my workspace");
+ stub(cache.findNodeInfo(uuid)).toReturn(info);
+ stub(cache.getPathFor(info)).toReturn(path("/a/b/c/d"));
+ stub(session.nodeTypeManager()).toReturn(nodeTypes);
+ node = new MockAbstractJcrNode(cache, uuid);
+
+ // Create the children container for the node ...
+ children = new Children(uuid);
+ stub(info.getChildren()).toReturn(children);
}
protected Name name( String name ) {
return context.getValueFactories().getNameFactory().create(name);
}
+ protected Path relativePath( String relativePath ) {
+ return context.getValueFactories().getPathFactory().create(relativePath);
+ }
+
+ protected Path path( String absolutePath ) {
+ return context.getValueFactories().getPathFactory().create(absolutePath);
+ }
+
+ protected Value stringValueFor( Object value ) {
+ return new JcrValue(context.getValueFactories(), PropertyType.STRING, value);
+ }
+
@Test
public void shouldAllowVisitation() throws Exception {
ItemVisitor visitor = Mockito.mock(ItemVisitor.class);
@@ -156,11 +161,6 @@
node.accept(null);
}
- @Test( expected = AssertionError.class )
- public void shouldNotAllowNoSession() throws Exception {
- new MockAbstractJcrNode(null, null, null);
- }
-
@Test( expected = ItemNotFoundException.class )
public void shouldNotAllowNegativeAncestorDepth() throws Exception {
node.getAncestor(-1);
@@ -172,20 +172,50 @@
}
@Test
- public void shouldProvideInternalUuid() throws Exception {
- UUID uuid = UUID.randomUUID();
- node.setInternalUuid(uuid);
- assertThat(node.internalUuid(), is(uuid));
+ public void shouldReturnPropertyFromGetPropertyWithValidName() throws Exception {
+ PropertyId propertyId = new PropertyId(uuid, name("test"));
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrProperty(propertyId)).toReturn(property);
+ assertThat(node.getProperty("test"), is((Property)property));
}
@Test
- public void shouldProvideNamedProperty() throws Exception {
- Property property = Mockito.mock(Property.class);
- stub(property.getName()).toReturn("test");
- properties.put(name(property.getName()), property);
- assertThat(node.getProperty("test"), is(property));
+ public void shouldReturnPropertyFromGetPropertyWithValidRelativePath() throws
Exception {
+ PropertyId propertyId = new PropertyId(uuid, name("test"));
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrProperty(propertyId)).toReturn(property);
+ assertThat(node.getProperty("test"), is((Property)property));
}
+ @Test( expected = PathNotFoundException.class )
+ public void
shouldFailToReturnPropertyFromGetPropertyWithNameOfPropertyThatDoesNotExist() throws
Exception {
+ node.getProperty("nonExistantProperty");
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToReturnPropertyFromGetPropertyWithAbsolutePath() throws
Exception {
+ node.getProperty("/test");
+ }
+
+ @Test( expected = PathNotFoundException.class )
+ public void
shouldFailToReturnPropertyFromGetPropertyWithRelativePathToNonExistantItem() throws
Exception {
+ node.getProperty("../bogus/path");
+ }
+
+ @Test
+ public void
shouldReturnPropertyFromGetPropertyWithRelativePathToPropertyOnOtherNode() throws
Exception {
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrItem(uuid,
relativePath("../good/path"))).toReturn(property);
+ assertThat(node.getProperty("../good/path"), is((Property)property));
+ }
+
+ @Test( expected = PathNotFoundException.class )
+ public void shouldReturnPropertyFromGetPropertyWithRelativePathToOtherNode() throws
Exception {
+ AbstractJcrNode otherNode = mock(AbstractJcrNode.class);
+ stub(cache.findJcrItem(uuid,
relativePath("../good/path"))).toReturn(otherNode);
+ node.getProperty("../good/path");
+ }
+
@Test( expected = UnsupportedOperationException.class )
public void shoudNotAllowAddMixin() throws Exception {
node.addMixin(null);
@@ -241,152 +271,210 @@
node.getLock();
}
- @Test
- public void shouldProvideNode() throws Exception {
- Node child = createChild(session, "child", 1, children, node);
- node.setChildren(children);
- stub(session.getItem("/node/child")).toReturn(child);
- assertThat(node.getNode("child"), is(child));
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowGetPropertyWithNullPath() throws Exception {
+ node.getProperty((String)null);
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetNodeWithNoPath() throws Exception {
- node.getNode(null);
+ public void shouldNotAllowGetPropertyWithEmptyPath() throws Exception {
+ node.getProperty("");
}
+ @Test
+ public void shouldReturnChildNodeFromGetNodeWithValidName() throws Exception {
+ AbstractJcrNode child = mock(AbstractJcrNode.class);
+ UUID childUuid = UUID.randomUUID();
+ children.append(cache, name("child"), childUuid);
+ stub(cache.findJcrNode(childUuid)).toReturn(child);
+ assertThat(node.getNode("child"), is((Node)child));
+ }
+
+ @Test
+ public void shouldReturnNonChildNodeFromGetNodeWithValidRelativePath() throws
Exception {
+ AbstractJcrNode otherNode = mock(AbstractJcrNode.class);
+ stub(cache.findJcrItem(uuid,
path("../other/node"))).toReturn(otherNode);
+ assertThat(node.getNode("../other/node"), is((Node)otherNode));
+ }
+
@Test( expected = PathNotFoundException.class )
- public void shouldNotProvideNodeIfPathNotFound() throws Exception {
- node.getNode("bogus");
+ public void shouldFailToReturnNodeFromGetNodeWithValidRelativePathToProperty() throws
Exception {
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrItem(uuid,
path("../other/node"))).toReturn(property);
+ node.getNode("../other/node");
}
@Test( expected = PathNotFoundException.class )
- public void shouldNotProvideNodeIfPathIsProperty() throws Exception {
- Property property = Mockito.mock(Property.class);
- stub(session.getItem("/property")).toReturn(property);
- node.getNode("property");
+ public void
shouldFailToReturnNodeFromGetNodeWithValidRelativePathToNoNodeOrProperty() throws
Exception {
+ node.getNode("../other/node");
}
@Test
- public void shouldProvideNodeIterator() throws Exception {
- assertThat(node.getNodes(), notNullValue());
+ public void shouldReturnSelfFromGetNodeWithRelativePathContainingOnlySelfReference()
throws Exception {
+ assertThat(node.getNode("."), is((Node)node));
}
@Test
- public void shoudProvidePrimaryItem() throws Exception {
- Property property = Mockito.mock(Property.class);
- stub(property.getName()).toReturn("jcr:primaryItemName");
- stub(property.getString()).toReturn("primaryItem");
- properties.put(name(property.getName()), property);
- Item primaryItem = Mockito.mock(Item.class);
- stub(session.getItem("/node/primaryItem")).toReturn(primaryItem);
- assertThat(node.getPrimaryItem(), is(primaryItem));
+ public void
shouldReturnParentFromGetNodeWithRelativePathContainingOnlyParentReference() throws
Exception {
+ AbstractJcrNode parent = mock(AbstractJcrNode.class);
+ UUID parentUuid = UUID.randomUUID();
+ stub(info.getParent()).toReturn(parentUuid);
+ stub(cache.findJcrNode(parentUuid)).toReturn(parent);
+ assertThat(node.getNode(".."), is((Node)parent));
}
- @Test( expected = ItemNotFoundException.class )
- public void shoudNotProvidePrimaryItemIfUnavailable() throws Exception {
- node.getPrimaryItem();
+ @Test( expected = PathNotFoundException.class )
+ public void shouldFailToReturnChildNodeFromGetNodeWithNameOfChildThatDoesNotExist()
throws Exception {
+ node.getNode("something");
}
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowGetNodeWithNoPath() throws Exception {
+ node.getNode(null);
+ }
+
@Test
- public void shouldProvideProperty() throws Exception {
- Property prop1 = Mockito.mock(Property.class);
- stub(prop1.getName()).toReturn("prop1");
- properties.put(name(prop1.getName()), prop1);
- assertThat(node.getProperty("prop1"), is(prop1));
- MockAbstractJcrNode child = createChild(session, "child", 1, children,
node);
- Map<Name, Property> properties = new HashMap<Name, Property>();
- child.setProperties(properties);
- Property prop2 = Mockito.mock(Property.class);
- stub(prop2.getName()).toReturn("prop2");
- stub(session.getItem("/node/child/prop2")).toReturn(prop2);
- properties.put(name(prop2.getName()), prop2);
- MockAbstractJcrNode prop3Node = createChild(session, "prop3", 1,
children, child);
- node.setChildren(children);
- assertThat(node.getProperty("child/prop2"), is(prop2));
- // Ensure we return a property even when a child exists with the same name
- Property prop3 = Mockito.mock(Property.class);
- stub(prop3.getName()).toReturn("prop3");
- properties.put(name(prop3.getName()), prop3);
- stub(session.getItem("/node/child/prop3")).toReturn(prop3Node);
- assertThat(node.getProperty("child/prop3"), is(prop3));
+ public void shouldProvideNodeIterator() throws Exception {
+ AbstractJcrNode child = mock(AbstractJcrNode.class);
+ UUID childUuid = UUID.randomUUID();
+ children.append(cache, name("child"), childUuid);
+ stub(cache.findJcrNode(childUuid)).toReturn(child);
+ NodeIterator iter = node.getNodes();
+ assertThat(iter, notNullValue());
+ assertThat(iter.getSize(), is(1L));
+ assertThat(iter.next(), is((Object)child));
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetPropertyWithNullPath() throws Exception {
- node.getProperty((String)null);
+ @Test
+ public void shoudReturnItemFromGetPrimaryItemIfItExists() throws Exception {
+ // Define the node type ...
+ Name primaryTypeName = name("thePrimaryType");
+ JcrNodeType primaryType = mock(JcrNodeType.class);
+ stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
+ stub(primaryType.getPrimaryItemName()).toReturn("thePrimaryItemName");
+ // Define the node info to use this primary type ...
+ stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
+ // Now make an item with the appropriate name ...
+ AbstractJcrNode child = mock(AbstractJcrNode.class);
+ stub(cache.findJcrItem(uuid,
path("thePrimaryItemName"))).toReturn(child);
+ // Now call the method ...
+ assertThat(node.getPrimaryItem(), is((Item)child));
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetPropertyWithEmptyPath() throws Exception {
- node.getProperty("");
+ @Test( expected = ItemNotFoundException.class )
+ public void
shoudFailToReturnItemFromGetPrimaryItemIfPrimaryTypeDoesNotHavePrimaryItemName() throws
Exception {
+ // Define the node type ...
+ Name primaryTypeName = name("thePrimaryType");
+ JcrNodeType primaryType = mock(JcrNodeType.class);
+ stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
+ stub(primaryType.getPrimaryItemName()).toReturn(null);
+ // Define the node info to use this primary type ...
+ stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
+ // Now call the method ...
+ node.getPrimaryItem();
}
- @Test( expected = PathNotFoundException.class )
- public void shouldNotProvideChildPropertyIfNotAvailable() throws Exception {
- node.getProperty("prop1");
+ @Test( expected = ItemNotFoundException.class )
+ public void
shoudFailToReturnItemFromGetPrimaryItemIfThePrimaryTypeAsInvalidPrimaryItemName() throws
Exception {
+ // Define the node type ...
+ Name primaryTypeName = name("thePrimaryType");
+ JcrNodeType primaryType = mock(JcrNodeType.class);
+ stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
+ stub(primaryType.getPrimaryItemName()).toReturn("/this/is/not/valid");
+ // Define the node info to use this primary type ...
+ stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
+ // Now call the method ...
+ node.getPrimaryItem();
}
- @Test( expected = PathNotFoundException.class )
- public void shouldNotProvideDescendentPropertyIfNotAvailable() throws Exception {
- MockAbstractJcrNode child = createChild(session, "child", 1, children,
node);
- Map<Name, Property> properties = new HashMap<Name, Property>();
- child.setProperties(properties);
- MockAbstractJcrNode propNode = createChild(session, "prop", 1,
children, child);
- node.setChildren(children);
- stub(session.getItem("/node/child/prop")).toReturn(propNode);
- node.getProperty("child/prop");
+ @Test( expected = ItemNotFoundException.class )
+ public void
shoudFailToReturnItemFromGetPrimaryItemIfTheNodeHasNoItemMatchingThatSpecifiedByThePrimaryType()
throws Exception {
+ // Define the node type ...
+ Name primaryTypeName = name("thePrimaryType");
+ JcrNodeType primaryType = mock(JcrNodeType.class);
+ stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
+ stub(primaryType.getPrimaryItemName()).toReturn("thePrimaryItemName");
+ // Define the node info to use this primary type ...
+ stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
+ // Now call the method ...
+ stub(cache.findJcrItem(uuid, path("thePrimaryItemName"))).toThrow(new
ItemNotFoundException());
+ node.getPrimaryItem();
}
@Test
- public void shouldNotAllowGetReferences() throws Exception {
+ public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoProperties()
throws Exception {
+ // Set up two properties (one containing references, the other not) ...
+ List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[]
{});
+ stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
+ // Now call the method ...
PropertyIterator iter = node.getReferences();
- assertThat(iter, is(notNullValue()));
assertThat(iter.getSize(), is(0L));
+ assertThat(iter.hasNext(), is(false));
}
@Test
+ public void
shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoReferenceProperties() throws
Exception {
+ // Set up two properties (one containing references, the other not) ...
+ AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
+ AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
+ List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[]
{propertyA, propertyB});
+ stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
+ stub(propertyA.getType()).toReturn(PropertyType.LONG);
+ stub(propertyB.getType()).toReturn(PropertyType.BOOLEAN);
+ // Now call the method ...
+ PropertyIterator iter = node.getReferences();
+ assertThat(iter.getSize(), is(0L));
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @Test
+ public void
shouldReturnIteratorFromGetReferencesWhenThereIsAtLeastOneReferenceProperty() throws
Exception {
+ // Set up two properties (one containing references, the other not) ...
+ AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
+ AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
+ List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[]
{propertyA, propertyB});
+ stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
+ stub(propertyA.getType()).toReturn(PropertyType.LONG);
+ stub(propertyB.getType()).toReturn(PropertyType.REFERENCE);
+ // Now call the method ...
+ PropertyIterator iter = node.getReferences();
+ assertThat(iter.getSize(), is(1L));
+ assertThat(iter.next(), is(sameInstance((Object)propertyB)));
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @Test
public void shouldProvideSession() throws Exception {
assertThat((JcrSession)node.getSession(), is(session));
}
@Test
public void shouldProvideUuidIfReferenceable() throws Exception {
- String uuid = "uuid";
- Property mixinProp = Mockito.mock(Property.class);
- stub(mixinProp.getName()).toReturn("jcr:mixinTypes");
- Value value = Mockito.mock(Value.class);
- stub(value.getString()).toReturn("mix:referenceable");
- stub(mixinProp.getValues()).toReturn(new Value[] {value});
- properties.put(name(mixinProp.getName()), mixinProp);
- Property uuidProp = Mockito.mock(Property.class);
- stub(uuidProp.getName()).toReturn("jcr:uuid");
- stub(uuidProp.getString()).toReturn(uuid);
- properties.put(name(uuidProp.getName()), uuidProp);
- assertThat(node.getUUID(), is(uuid));
+ // Create the property ...
+ PropertyId propertyId = new PropertyId(uuid, name("jcr:mixinTypes"));
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrProperty(propertyId)).toReturn(property);
+ stub(property.getValues()).toReturn(new Value[]
{stringValueFor("acme:someMixin"),
stringValueFor("mix:referenceable")});
+ // Call the method ...
+ assertThat(node.getUUID(), is(uuid.toString()));
}
@Test( expected = UnsupportedRepositoryOperationException.class )
public void shouldNotProvideUuidIfNotReferenceable() throws Exception {
- String uuid = "uuid";
- Property mixinProp = Mockito.mock(Property.class);
- stub(mixinProp.getName()).toReturn("jcr:mixinTypes");
- Value value = Mockito.mock(Value.class);
- stub(mixinProp.getValues()).toReturn(new Value[] {value});
- properties.put(name(mixinProp.getName()), mixinProp);
- Property uuidProp = Mockito.mock(Property.class);
- stub(uuidProp.getName()).toReturn("jcr:uuid");
- stub(uuidProp.getString()).toReturn(uuid);
- properties.put(name(uuidProp.getName()), uuidProp);
+ // Create the property ...
+ PropertyId propertyId = new PropertyId(uuid, name("jcr:mixinTypes"));
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrProperty(propertyId)).toReturn(property);
+ stub(property.getValues()).toReturn(new Value[]
{stringValueFor("acme:someMixin"),
stringValueFor("mix:notReferenceable")});
+ // Call the method ...
node.getUUID();
}
@Test( expected = UnsupportedRepositoryOperationException.class )
public void shouldNotProvideUuidIfNoMixinTypes() throws Exception {
- String uuid = "uuid";
- Property uuidProp = Mockito.mock(Property.class);
- stub(uuidProp.getName()).toReturn("jcr:uuid");
- stub(uuidProp.getString()).toReturn(uuid);
- properties.put(name(uuidProp.getName()), uuidProp);
+ PropertyId propertyId = new PropertyId(uuid, name("jcr:mixinTypes"));
+ stub(cache.findJcrProperty(propertyId)).toReturn(null);
+ // Call the method ...
node.getUUID();
}
@@ -395,76 +483,134 @@
node.getVersionHistory();
}
- @Test
- public void shouldProvideHasNode() throws Exception {
- assertThat(node.hasNode("{}child"), is(false));
- Property prop = Mockito.mock(Property.class);
- stub(prop.getName()).toReturn("prop");
- properties.put(name(prop.getName()), prop);
- assertThat(node.hasNode("prop"), is(false));
- AbstractJcrNode child = createChild(session, "child", 1, children,
node);
- AbstractJcrNode child2 = createChild(session, "child2", 1, children,
child);
- node.setChildren(children);
- assertThat(node.hasNode("child"), is(true));
- stub(session.getItem("/node/child/{}child2")).toReturn(child2);
- assertThat(node.hasNode("child/{}child2"), is(true));
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullPathInHasNode() throws Exception {
+ node.hasNode((String)null);
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasNodeWithNoPath() throws Exception {
- node.hasNode(null);
+ public void shouldNotAllowEmptyPathInHasNode() throws Exception {
+ node.hasNode("");
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasNodeWithEmptyPath() throws Exception {
- node.hasNode("");
+ public void shouldNotAbsolutePathInHasNode() throws Exception {
+ node.hasNode("/a/b/c");
}
@Test
- public void shouldProvideHasNodes() throws Exception {
- assertThat(node.hasNodes(), is(false));
- createChild(session, "child", 1, children, node);
- node.setChildren(children);
- assertThat(node.hasNodes(), is(true));
+ public void shouldReturnTrueFromHasNodeWithSelfReference() throws Exception {
+ assertThat(node.hasNode("."), is(true));
}
@Test
- public void shouldProvideHasProperties() throws Exception {
- assertThat(node.hasProperties(), is(false));
- properties.put(name("something"), Mockito.mock(Property.class));
- assertThat(node.hasProperties(), is(true));
+ public void shouldReturnTrueFromHasNodeWithParentReferenceIfNotRootNode() throws
Exception {
+ assertThat(node.hasNode(".."), is(!node.isRoot()));
}
@Test
- public void shouldIndicateHasProperty() throws Exception {
- assertThat(node.hasProperty("prop"), is(false));
- MockAbstractJcrNode child = createChild(session, "child", 1, children,
node);
- node.setChildren(children);
- assertThat(node.hasProperty("child"), is(false));
- Property prop = Mockito.mock(Property.class);
- stub(prop.getName()).toReturn("prop");
- properties.put(name(prop.getName()), prop);
- assertThat(node.hasProperty("prop"), is(true));
- Map<Name, Property> properties = new HashMap<Name, Property>();
- child.setProperties(properties);
- Property prop2 = Mockito.mock(Property.class);
- stub(prop2.getName()).toReturn("prop2");
- properties.put(name(prop2.getName()), prop2);
- stub(session.getItem("/node/child/prop2")).toReturn(prop2);
- assertThat(node.hasProperty("child/prop2"), is(true));
+ public void shouldReturnTrueFromHasNodeIfRelativePathIdentifiesExistingNode() throws
Exception {
+ AbstractJcrNode otherNode = mock(AbstractJcrNode.class);
+ stub(cache.findJcrNode(uuid,
path("../other/node"))).toReturn(otherNode);
+ assertThat(node.hasNode("../other/node"), is(true));
}
+ @Test
+ public void shouldReturnTrueFromHasNodeIfChildWithNameExists() throws Exception {
+ children.append(cache, name("child"), UUID.randomUUID());
+ assertThat(node.hasNode("child[1]"), is(true));
+ assertThat(node.hasNode("child[2]"), is(false));
+ children.append(cache, name("child"), UUID.randomUUID());
+ assertThat(node.hasNode("child[2]"), is(true));
+ assertThat(node.hasNode("child[3]"), is(false));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasNodeWithNameOfChildThatDoesNotExist() throws
Exception {
+ assertThat(node.hasNode("something"), is(false));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasNodesIfThereAreNoChildren() throws Exception {
+ assertThat(node.hasNodes(), is(false));
+ }
+
+ @Test
+ public void shouldReturnTrueFromHasNodesIfThereIsAtLeastOneChild() throws Exception
{
+ children.append(cache, name("child"), UUID.randomUUID());
+ assertThat(node.hasNodes(), is(true));
+ }
+
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasPropertyWithNoPath() throws Exception {
- node.hasProperty(null);
+ public void shouldNotAllowNullPathInHasProperty() throws Exception {
+ node.hasProperty((String)null);
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowHasPropertyWithEmptyPath() throws Exception {
+ public void shouldNotAllowEmptyPathInHasProperty() throws Exception {
node.hasProperty("");
}
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAbsolutePathInHasProperty() throws Exception {
+ node.hasProperty("/a/b/c");
+ }
+
@Test
+ public void
shouldReturnTrueFromHasPropertyIfPathIsRelativePathToOtherNodeWithNamedProperty() throws
Exception {
+ AbstractJcrProperty property = mock(AbstractJcrProperty.class);
+ stub(cache.findJcrItem(uuid,
relativePath("../good/path"))).toReturn(property);
+ assertThat(node.hasProperty("../good/path"), is(true));
+ }
+
+ @Test
+ public void
shouldReturnFalseFromHasPropertyIfPathIsRelativePathToOtherNodeWithoutNamedProperty()
throws Exception {
+ stub(cache.findJcrItem(uuid, relativePath("../good/path"))).toThrow(new
PathNotFoundException());
+ assertThat(node.hasProperty("../good/path"), is(false));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasPropertyIfPathIsParentPath() throws Exception {
+ assertThat(node.hasProperty(".."), is(false));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasPropertyIfPathIsSelfPath() throws Exception {
+ assertThat(node.hasProperty("."), is(false));
+ }
+
+ @Test
+ public void shouldReturnTrueFromHasPropertyIfPathIsNameAndNodeHasProperty() throws
Exception {
+ PropertyInfo propertyInfo = mock(PropertyInfo.class);
+ stub(cache.findPropertyInfo(new PropertyId(uuid,
name("prop")))).toReturn(propertyInfo);
+ assertThat(node.hasProperty("prop"), is(true));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasPropertyIfPathIsNameAndNodeDoesNotHaveProperty()
throws Exception {
+ stub(cache.findPropertyInfo(new PropertyId(uuid,
name("prop")))).toReturn(null);
+ assertThat(node.hasProperty("prop"), is(false));
+ }
+
+ @Test
+ @SuppressWarnings( "unchecked" )
+ public void shouldReturnTrueFromHasPropertiesIfNodeHasAtLeastOneProperty() throws
Exception {
+ Map<Name, PropertyInfo> properties = mock(Map.class);
+ stub(properties.size()).toReturn(5);
+ stub(info.getProperties()).toReturn(properties);
+ assertThat(node.hasProperties(), is(true));
+ }
+
+ @Test
+ @SuppressWarnings( "unchecked" )
+ public void shouldReturnFalseFromHasPropertiesIfNodeHasNoProperties() throws
Exception {
+ Map<Name, PropertyInfo> properties = mock(Map.class);
+ stub(properties.size()).toReturn(0);
+ stub(info.getProperties()).toReturn(properties);
+ assertThat(node.hasProperties(), is(false));
+ }
+
+ @Test
public void shouldNotAllowHoldsLock() throws Exception {
assertThat(node.holdsLock(), is(false));
}
@@ -485,29 +631,87 @@
}
@Test
- public void shouldProvideIsSame() throws Exception {
- stub(session.getWorkspace()).toReturn(Mockito.mock(Workspace.class));
- stub(session.getRepository()).toReturn(repository);
+ public void shouldReturnFalseFromIsSameIfTheRepositoryInstanceIsDifferent() throws
Exception {
+ Workspace workspace1 = mock(Workspace.class);
+ Repository repository1 = mock(Repository.class);
+ stub(session.getWorkspace()).toReturn(workspace1);
+ stub(session.getRepository()).toReturn(repository1);
+ stub(workspace1.getName()).toReturn("workspace1");
+
+ Workspace workspace2 = mock(Workspace.class);
JcrSession session2 = Mockito.mock(JcrSession.class);
- JcrRepository repository2 = Mockito.mock(JcrRepository.class);
+ Repository repository2 = mock(Repository.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session2.getRepository()).toReturn(repository2);
+ stub(workspace2.getName()).toReturn("workspace1");
+ stub(cache2.session()).toReturn(session2);
- stub(session2.getRepository()).toReturn(repository2);
- stub(session2.getWorkspace()).toReturn(workspace);
- Node node2 = new MockAbstractJcrNode(session2, node.getName(),
node.getParent());
+ UUID uuid2 = uuid;
+ Node node2 = new MockAbstractJcrNode(cache2, uuid2);
assertThat(node.isSame(node2), is(false));
+ }
- Property prop = Mockito.mock(Property.class);
- stub(prop.getSession()).toReturn(session);
- assertThat(node.isSame(prop), is(false));
- node2 = Mockito.mock(Node.class);
- stub(node2.getSession()).toReturn(session);
+ @Test
+ public void shouldReturnFalseFromIsSameIfTheWorkspaceNameIsDifferent() throws
Exception {
+ Workspace workspace1 = mock(Workspace.class);
+ Repository repository1 = mock(Repository.class);
+ stub(session.getWorkspace()).toReturn(workspace1);
+ stub(session.getRepository()).toReturn(repository1);
+ stub(workspace1.getName()).toReturn("workspace1");
+
+ Workspace workspace2 = mock(Workspace.class);
+ JcrSession session2 = Mockito.mock(JcrSession.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session2.getRepository()).toReturn(repository1);
+ stub(workspace2.getName()).toReturn("workspace2");
+ stub(cache2.session()).toReturn(session2);
+
+ UUID uuid2 = uuid;
+ Node node2 = new MockAbstractJcrNode(cache2, uuid2);
assertThat(node.isSame(node2), is(false));
- node2 = new MockAbstractJcrNode(session, node.getName(), node.getParent());
- UUID uuid = UUID.randomUUID();
- node.setInternalUuid(uuid);
- ((MockAbstractJcrNode)node2).setInternalUuid(UUID.randomUUID());
+ }
+
+ @Test
+ public void shouldReturnFalseFromIsSameIfTheNodeUuidIsDifferent() throws Exception {
+ Workspace workspace1 = mock(Workspace.class);
+ Repository repository1 = mock(Repository.class);
+ stub(session.getWorkspace()).toReturn(workspace1);
+ stub(session.getRepository()).toReturn(repository1);
+ stub(workspace1.getName()).toReturn("workspace1");
+
+ Workspace workspace2 = mock(Workspace.class);
+ JcrSession session2 = Mockito.mock(JcrSession.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session2.getRepository()).toReturn(repository1);
+ stub(workspace2.getName()).toReturn("workspace1");
+ stub(cache2.session()).toReturn(session2);
+
+ UUID uuid2 = UUID.randomUUID();
+ Node node2 = new MockAbstractJcrNode(cache2, uuid2);
assertThat(node.isSame(node2), is(false));
- ((MockAbstractJcrNode)node2).setInternalUuid(uuid);
+ }
+
+ @Test
+ public void
shouldReturnTrueFromIsSameIfTheNodeUuidAndWorkspaceNameAndRepositoryInstanceAreSame()
throws Exception {
+ Workspace workspace1 = mock(Workspace.class);
+ Repository repository1 = mock(Repository.class);
+ stub(session.getWorkspace()).toReturn(workspace1);
+ stub(session.getRepository()).toReturn(repository1);
+ stub(workspace1.getName()).toReturn("workspace1");
+
+ Workspace workspace2 = mock(Workspace.class);
+ JcrSession session2 = Mockito.mock(JcrSession.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session2.getRepository()).toReturn(repository1);
+ stub(workspace2.getName()).toReturn("workspace1");
+ stub(cache2.session()).toReturn(session2);
+
+ UUID uuid2 = uuid;
+ Node node2 = new MockAbstractJcrNode(cache2, uuid2);
assertThat(node.isSame(node2), is(true));
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -25,6 +25,7 @@
import static org.hamcrest.core.Is.is;
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.Calendar;
@@ -34,17 +35,16 @@
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
import javax.jcr.Property;
-import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.Workspace;
-import javax.jcr.nodetype.NodeDefinition;
-import javax.jcr.nodetype.PropertyDefinition;
import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.jcr.SessionCache.NodeInfo;
+import org.jboss.dna.jcr.SessionCache.PropertyInfo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
@@ -56,48 +56,54 @@
*/
public class AbstractJcrPropertyTest {
+ private PropertyId propertyId;
+ private PropertyInfo info;
+ private ExecutionContext executionContext;
+ private JcrNode node;
private AbstractJcrProperty prop;
@Mock
- private Workspace workspace;
- @Mock
- private Repository repository;
- @Mock
private JcrSession session;
- private AbstractJcrNode node;
@Mock
- private NodeDefinition nodeDefinition;
- @Mock
- private PropertyDefinition propertyDefinition;
- private ExecutionContext executionContext;
- private org.jboss.dna.graph.property.Property dnaProperty;
- private Location rootLocation;
- private Location nodeLocation;
+ private SessionCache cache;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
executionContext = new ExecutionContext();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
"text/plain");
- stub(propertyDefinition.getRequiredType()).toReturn(PropertyType.STRING);
- stub(session.getWorkspace()).toReturn(workspace);
- stub(session.getRepository()).toReturn(repository);
stub(session.getExecutionContext()).toReturn(executionContext);
- UUID rootUuid = UUID.randomUUID();
- Path rootPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
- rootLocation = Location.create(rootPath, rootUuid);
- JcrRootNode rootNode = new JcrRootNode(session, rootLocation, nodeDefinition);
- stub(session.getNode(rootUuid)).toReturn(rootNode);
-
UUID uuid = UUID.randomUUID();
- Path path =
executionContext.getValueFactories().getPathFactory().create("/nodeName");
- nodeLocation = Location.create(path, uuid);
- node = new JcrNode(session, rootUuid, nodeLocation, nodeDefinition);
- stub(session.getNode(uuid)).toReturn(node);
+ node = new JcrNode(cache, uuid);
+ propertyId = new PropertyId(uuid, JcrLexicon.MIMETYPE);
+ prop = new MockAbstractJcrProperty(cache, propertyId);
- prop = new MockAbstractJcrProperty(node, propertyDefinition, dnaProperty);
+ info = mock(PropertyInfo.class);
+ stub(info.getPropertyId()).toReturn(propertyId);
+ stub(info.getPropertyName()).toReturn(propertyId.getPropertyName());
+
+ stub(cache.session()).toReturn(session);
+ stub(cache.context()).toReturn(executionContext);
+ stub(cache.findJcrProperty(propertyId)).toReturn(prop);
+ stub(cache.findPropertyInfo(propertyId)).toReturn(info);
+ stub(cache.getPathFor(info)).toReturn(path("/a/b/c/jcr:mimeType"));
+
stub(cache.getPathFor(propertyId)).toReturn(path("/a/b/c/jcr:mimeType"));
+ stub(cache.getPathFor(uuid)).toReturn(path("/a/b/c"));
+
+ NodeInfo nodeInfo = mock(NodeInfo.class);
+ stub(cache.findJcrNode(uuid)).toReturn(node);
+ stub(cache.findNodeInfo(uuid)).toReturn(nodeInfo);
+ stub(cache.getPathFor(uuid)).toReturn(path("/a/b/c"));
+ stub(cache.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
}
+ protected Name name( String name ) {
+ return executionContext.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path path( String path ) {
+ return executionContext.getValueFactories().getPathFactory().create(path);
+ }
+
@Test
public void shouldAllowVisitation() throws Exception {
ItemVisitor visitor = Mockito.mock(ItemVisitor.class);
@@ -123,18 +129,18 @@
}
@Test( expected = ItemNotFoundException.class )
- public void shouldNotAllowAncestorDepthGreaterThanNodeDepth() throws Exception {
- prop.getAncestor(3);
+ public void shouldNotAllowAncestorDepthGreaterThanPropertyDepth() throws Exception {
+ prop.getAncestor(prop.getDepth() + 1);
}
@Test
public void shouldProvideDepth() throws Exception {
- assertThat(prop.getDepth(), is(2));
+ assertThat(prop.getDepth(), is(4));
}
@Test
public void shouldProvideExecutionContext() throws Exception {
- assertThat(prop.getExecutionContext(), is(executionContext));
+ assertThat(prop.context(), is(executionContext));
}
@Test
@@ -149,7 +155,7 @@
@Test
public void shouldProvidePath() throws Exception {
- assertThat(prop.getPath(), is("/nodeName/jcr:mimeType"));
+ assertThat(prop.getPath(), is("/a/b/c/jcr:mimeType"));
}
@Test
@@ -163,43 +169,111 @@
}
@Test
- public void shouldIndicateSameAsNodeWithSameParentAndSamePropertyName() throws
Exception {
- org.jboss.dna.graph.property.Property otherDnaProperty =
executionContext.getPropertyFactory()
-
.create(dnaProperty.getName());
+ public void shouldIndicateSameAsPropertyWithSameNodeAndSamePropertyName() throws
Exception {
+ Repository repository = mock(Repository.class);
+ Workspace workspace = mock(Workspace.class);
+ Workspace workspace2 = mock(Workspace.class);
+ stub(workspace.getName()).toReturn("workspace");
+ stub(workspace2.getName()).toReturn("workspace");
+ JcrSession session2 = mock(JcrSession.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getRepository()).toReturn(repository);
+ stub(session.getRepository()).toReturn(repository);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session.getWorkspace()).toReturn(workspace);
+ stub(cache2.session()).toReturn(session2);
+ stub(cache2.context()).toReturn(executionContext);
+
// Make the other node have the same UUID ...
- JcrNode otherNode = new JcrNode(session, rootLocation.getUuid(), nodeLocation,
nodeDefinition);
+ UUID uuid = node.internalUuid();
+ NodeInfo nodeInfo = mock(NodeInfo.class);
+ PropertyInfo propertyInfo = mock(PropertyInfo.class);
+ AbstractJcrNode otherNode = new JcrNode(cache2, uuid);
+ stub(propertyInfo.getPropertyId()).toReturn(propertyId);
+ stub(propertyInfo.getPropertyName()).toReturn(propertyId.getPropertyName());
+ stub(cache2.findJcrNode(uuid)).toReturn(otherNode);
+ stub(cache2.findNodeInfo(uuid)).toReturn(nodeInfo);
+ stub(cache2.getPathFor(uuid)).toReturn(path("/a/b/c"));
+ stub(cache2.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
+ stub(cache2.findPropertyInfo(propertyId)).toReturn(info);
assertThat(node.isSame(otherNode), is(true));
- Property prop = new MockAbstractJcrProperty(node, propertyDefinition,
otherDnaProperty);
- Property otherProp = new MockAbstractJcrProperty(otherNode, propertyDefinition,
otherDnaProperty);
+
+ Property prop = new MockAbstractJcrProperty(cache, propertyId);
+ Property otherProp = new MockAbstractJcrProperty(cache2, propertyId);
assertThat(prop.isSame(otherProp), is(true));
}
@Test
public void shouldIndicateDifferentThanNodeWithDifferentParent() throws Exception {
- org.jboss.dna.graph.property.Property otherDnaProperty =
executionContext.getPropertyFactory()
-
.create(dnaProperty.getName());
- UUID otherUuid = UUID.randomUUID();
- Path otherPath =
executionContext.getValueFactories().getPathFactory().create("/nodeName");
- Location location = Location.create(otherPath, otherUuid);
- JcrNode otherNode = new JcrNode(session, rootLocation.getUuid(), location,
nodeDefinition);
- stub(session.getNode(otherUuid)).toReturn(otherNode);
+ Repository repository = mock(Repository.class);
+ Workspace workspace = mock(Workspace.class);
+ Workspace workspace2 = mock(Workspace.class);
+ stub(workspace.getName()).toReturn("workspace");
+ stub(workspace2.getName()).toReturn("workspace");
+ JcrSession session2 = mock(JcrSession.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getRepository()).toReturn(repository);
+ stub(session.getRepository()).toReturn(repository);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session.getWorkspace()).toReturn(workspace);
+ stub(cache2.session()).toReturn(session2);
+ stub(cache2.context()).toReturn(executionContext);
+ // Make the other node have a different UUID ...
+ UUID uuid = UUID.randomUUID();
+ PropertyId propertyId2 = new PropertyId(uuid, JcrLexicon.MIXIN_TYPES);
+ NodeInfo nodeInfo = mock(NodeInfo.class);
+ PropertyInfo propertyInfo = mock(PropertyInfo.class);
+ AbstractJcrNode otherNode = new JcrNode(cache2, uuid);
+ stub(propertyInfo.getPropertyId()).toReturn(propertyId2);
+ stub(propertyInfo.getPropertyName()).toReturn(propertyId2.getPropertyName());
+ stub(cache2.findJcrNode(uuid)).toReturn(otherNode);
+ stub(cache2.findNodeInfo(uuid)).toReturn(nodeInfo);
+ stub(cache2.getPathFor(uuid)).toReturn(path("/a/b/c"));
+ stub(cache2.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
+
assertThat(node.isSame(otherNode), is(false));
- Property prop = new MockAbstractJcrProperty(node, propertyDefinition,
otherDnaProperty);
- Property otherProp = new MockAbstractJcrProperty(otherNode, propertyDefinition,
otherDnaProperty);
+
+ Property prop = new MockAbstractJcrProperty(cache, propertyId);
+ Property otherProp = new MockAbstractJcrProperty(cache2, propertyId2);
assertThat(prop.isSame(otherProp), is(false));
}
@Test
public void
shouldIndicateDifferentThanPropertyWithSameNodeWithDifferentPropertyName() throws
Exception {
- org.jboss.dna.graph.property.Property otherDnaProperty =
executionContext.getPropertyFactory().create(JcrLexicon.NAME);
+ Repository repository = mock(Repository.class);
+ Workspace workspace = mock(Workspace.class);
+ Workspace workspace2 = mock(Workspace.class);
+ stub(workspace.getName()).toReturn("workspace");
+ stub(workspace2.getName()).toReturn("workspace");
+ JcrSession session2 = mock(JcrSession.class);
+ SessionCache cache2 = mock(SessionCache.class);
+ stub(session2.getRepository()).toReturn(repository);
+ stub(session.getRepository()).toReturn(repository);
+ stub(session2.getWorkspace()).toReturn(workspace2);
+ stub(session.getWorkspace()).toReturn(workspace);
+ stub(cache2.session()).toReturn(session2);
+ stub(cache2.context()).toReturn(executionContext);
+
// Make the other node have the same UUID ...
- JcrNode otherNode = new JcrNode(session, rootLocation.getUuid(), nodeLocation,
nodeDefinition);
+ UUID uuid = node.internalUuid();
+ NodeInfo nodeInfo = mock(NodeInfo.class);
+ PropertyInfo propertyInfo = mock(PropertyInfo.class);
+ PropertyId propertyId2 = new PropertyId(uuid, JcrLexicon.NAME);
+ AbstractJcrNode otherNode = new JcrNode(cache2, uuid);
+ stub(propertyInfo.getPropertyId()).toReturn(propertyId2);
+ stub(propertyInfo.getPropertyName()).toReturn(propertyId2.getPropertyName());
+ stub(cache2.findJcrNode(uuid)).toReturn(otherNode);
+ stub(cache2.findNodeInfo(uuid)).toReturn(nodeInfo);
+ stub(cache2.getPathFor(uuid)).toReturn(path("/a/b/c"));
+ stub(cache2.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
+ stub(cache2.findPropertyInfo(propertyId2)).toReturn(propertyInfo);
assertThat(node.isSame(otherNode), is(true));
- Property prop = new MockAbstractJcrProperty(node, propertyDefinition,
dnaProperty);
- Property otherProp = new MockAbstractJcrProperty(otherNode, propertyDefinition,
otherDnaProperty);
+
+ Property prop = new MockAbstractJcrProperty(cache, propertyId);
+ Property otherProp = new MockAbstractJcrProperty(cache2, propertyId2);
assertThat(prop.isSame(otherProp), is(false));
}
@@ -255,10 +329,9 @@
private class MockAbstractJcrProperty extends AbstractJcrProperty {
- MockAbstractJcrProperty( AbstractJcrNode node,
- PropertyDefinition propertyDefinition,
- org.jboss.dna.graph.property.Property dnaProperty ) {
- super(node, propertyDefinition, propertyDefinition.getRequiredType(),
dnaProperty);
+ MockAbstractJcrProperty( SessionCache cache,
+ PropertyId propertyId ) {
+ super(cache, propertyId);
}
/**
@@ -266,8 +339,9 @@
*
* @see javax.jcr.Property#getNode()
*/
+ @SuppressWarnings( "synthetic-access" )
public Node getNode() {
- throw new UnsupportedOperationException(); // shouldn't be called
+ return node;
}
/**
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java
(rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -0,0 +1,112 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import org.jboss.dna.graph.property.basic.BasicName;
+import org.jboss.dna.jcr.SessionCache.ChildNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ *
+ */
+public class JcrChildNodeIteratorTest {
+
+ private List<ChildNode> children;
+ private List<Node> childNodes;
+ private NodeIterator iter;
+ @Mock
+ private SessionCache cache;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ children = new ArrayList<ChildNode>();
+ childNodes = new ArrayList<Node>();
+ for (int i = 0; i != 10; ++i) {
+ UUID uuid = UUID.randomUUID();
+ ChildNode child = new ChildNode(uuid, new BasicName("",
"name"), i + 1);
+ AbstractJcrNode node = mock(AbstractJcrNode.class);
+ stub(cache.findJcrNode(uuid)).toReturn(node);
+ children.add(child);
+ childNodes.add(node);
+ }
+ iter = new JcrChildNodeIterator(cache, children, children.size());
+ }
+
+ @Test
+ public void shouldProperlyDetermineHasNext() {
+ Iterator<Node> nodeIter = childNodes.iterator();
+ long position = 0L;
+ assertThat(iter.getPosition(), is(position));
+ while (iter.hasNext()) {
+ assertThat(nodeIter.hasNext(), is(true));
+ Node actual = (Node)iter.next();
+ Node expected = nodeIter.next();
+ assertThat(iter.getPosition(), is(++position));
+ assertThat(iter.getPosition(), is(position)); // call twice
+ assertThat(actual, is(sameInstance(expected)));
+ }
+ assertThat(iter.hasNext(), is(false));
+ assertThat(nodeIter.hasNext(), is(false));
+ }
+
+ @Test
+ public void shouldStartWithPositionOfZero() {
+ assertThat(iter.getPosition(), is(0L));
+ }
+
+ @Test
+ public void shouldHaveCorrectSize() {
+ assertThat(iter.getSize(), is((long)childNodes.size()));
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldNotAllowRemove() {
+ iter.remove();
+ }
+
+ @Test( expected = NoSuchElementException.class )
+ public void shouldFailWhenNextIsCalled() {
+ while (iter.hasNext()) {
+ iter.next();
+ }
+ iter.next();
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyNodeIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyNodeIteratorTest.java
(rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyNodeIteratorTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -0,0 +1,70 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.util.NoSuchElementException;
+import javax.jcr.NodeIterator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JcrEmptyNodeIteratorTest {
+
+ private NodeIterator iter;
+
+ @Before
+ public void beforeEach() {
+ iter = new JcrEmptyNodeIterator();
+ }
+
+ @Test
+ public void shouldNotHaveNext() {
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @Test
+ public void shouldHavePositionOfZero() {
+ assertThat(iter.getPosition(), is(0L));
+ }
+
+ @Test
+ public void shouldHaveSizeOfZero() {
+ assertThat(iter.getSize(), is(0L));
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldNotAllowRemove() {
+ iter.remove();
+ }
+
+ @Test( expected = NoSuchElementException.class )
+ public void shouldFailWhenNextIsCalled() {
+ iter.next();
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyNodeIteratorTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyPropertyIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyPropertyIteratorTest.java
(rev 0)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyPropertyIteratorTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -0,0 +1,70 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.util.NoSuchElementException;
+import javax.jcr.PropertyIterator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JcrEmptyPropertyIteratorTest {
+
+ private PropertyIterator iter;
+
+ @Before
+ public void beforeEach() {
+ iter = new JcrEmptyPropertyIterator();
+ }
+
+ @Test
+ public void shouldNotHaveNext() {
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @Test
+ public void shouldHavePositionOfZero() {
+ assertThat(iter.getPosition(), is(0L));
+ }
+
+ @Test
+ public void shouldHaveSizeOfZero() {
+ assertThat(iter.getSize(), is(0L));
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldNotAllowRemove() {
+ iter.remove();
+ }
+
+ @Test( expected = NoSuchElementException.class )
+ public void shouldFailWhenNextIsCalled() {
+ iter.next();
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrEmptyPropertyIteratorTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
===================================================================
---
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java 2009-03-12
20:54:55 UTC (rev 776)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -28,15 +28,13 @@
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.stub;
import java.util.UUID;
-import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.PropertyDefinition;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.jcr.SessionCache.PropertyInfo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -47,34 +45,50 @@
*/
public class JcrMultiValuePropertyTest {
- private Property prop;
- private AbstractJcrNode node;
+ private PropertyId propertyId;
+ private JcrMultiValueProperty prop;
private ExecutionContext executionContext;
+ private org.jboss.dna.graph.property.Property dnaProperty;
@Mock
+ private SessionCache cache;
+ @Mock
private JcrSession session;
@Mock
- private NodeDefinition nodeDefinition;
+ private PropertyInfo propertyInfo;
@Mock
- private PropertyDefinition definition;
- private org.jboss.dna.graph.property.Property dnaProperty;
+ private JcrPropertyDefinition definition;
+ @Mock
+ private JcrNodeTypeManager nodeTypes;
@Before
- public void before() {
+ public void before() throws Exception {
MockitoAnnotations.initMocks(this);
executionContext = new ExecutionContext();
+ stub(cache.session()).toReturn(session);
+ stub(cache.context()).toReturn(executionContext);
+ stub(session.nodeTypeManager()).toReturn(nodeTypes);
- UUID rootUuid = UUID.randomUUID();
- Path rootPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
- Location rootLocation = Location.create(rootPath, rootUuid);
- node = new JcrRootNode(session, rootLocation, nodeDefinition);
- stub(session.getExecutionContext()).toReturn(executionContext);
-
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
true);
stub(definition.getRequiredType()).toReturn(PropertyType.BOOLEAN);
stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(node, definition, definition.getRequiredType(),
dnaProperty);
+ PropertyDefinitionId definitionId = new
PropertyDefinitionId(name("nodeTypeName"), name("propDefnName"));
+ stub(nodeTypes.getPropertyDefinition(definitionId, true)).toReturn(definition);
+
+ UUID uuid = UUID.randomUUID();
+ propertyId = new PropertyId(uuid, JcrLexicon.MIMETYPE);
+ prop = new JcrMultiValueProperty(cache, propertyId);
+
+ stub(cache.findPropertyInfo(propertyId)).toReturn(propertyInfo);
+ stub(propertyInfo.getDefinitionId()).toReturn(definitionId);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.BOOLEAN);
+ stub(propertyInfo.isMultiValued()).toReturn(true);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
}
+ protected Name name( String name ) {
+ return executionContext.getValueFactories().getNameFactory().create(name);
+ }
+
@Test
public void shouldProvideAppropriateType() throws Exception {
assertThat(prop.getType(), is(definition.getRequiredType()));
@@ -82,7 +96,7 @@
@Test
public void shouldProvidePropertyDefinition() throws Exception {
- assertThat(prop.getDefinition(), notNullValue());
+ assertThat(prop.getDefinition(), is((PropertyDefinition)definition));
}
@Test
@@ -149,9 +163,10 @@
Object value = "value";
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
value);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(node, definition, definition.getRequiredType(),
dnaProperty);
+ prop = new JcrMultiValueProperty(cache, propertyId);
lengths = prop.getLengths();
assertThat(lengths, notNullValue());
assertThat(lengths.length, is(1));
@@ -160,9 +175,10 @@
value = new Object();
long expectedLength =
executionContext.getValueFactories().getBinaryFactory().create(value).getSize();
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
value);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(node, definition, definition.getRequiredType(),
dnaProperty);
+ prop = new JcrMultiValueProperty(cache, propertyId);
lengths = prop.getLengths();
assertThat(lengths, notNullValue());
assertThat(lengths.length, is(1));
@@ -170,9 +186,10 @@
String[] values = new String[] {"value1", "value2",
"value 3 is longer"};
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
(Object[])values);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(node, definition, definition.getRequiredType(),
dnaProperty);
+ prop = new JcrMultiValueProperty(cache, propertyId);
lengths = prop.getLengths();
assertThat(lengths, notNullValue());
assertThat(lengths.length, is(values.length));
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeIteratorTest.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeIteratorTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -1,101 +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.jcr;
-
-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.stub;
-import java.util.ArrayList;
-import java.util.List;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.jcr.AbstractJcrNodeTest.MockAbstractJcrNode;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author jverhaeg
- */
-public class JcrNodeIteratorTest {
-
- private AbstractJcrNode node;
- @Mock
- private JcrSession session;
- private List<Location> children;
-
- @Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
- ExecutionContext context = new ExecutionContext();
- stub(session.getExecutionContext()).toReturn(context);
- children = new ArrayList<Location>();
- node = new MockAbstractJcrNode(session, "node", null);
- }
-
- @Test
- public void shouldProvideNodeIterator() throws Exception {
- Node child1 = AbstractJcrNodeTest.createChild(session, "child1", 1,
children, node);
- Node child2_1 = AbstractJcrNodeTest.createChild(session, "child2", 1,
children, node);
- Node child2_2 = AbstractJcrNodeTest.createChild(session, "child2", 2,
children, node);
- AbstractJcrNodeTest.createChild(session, "child3", 1, children, node);
- AbstractJcrNodeTest.createChild(session, "child4", 1, children, node);
- Node child5 = AbstractJcrNodeTest.createChild(session, "child5", 1,
children, node);
- node.setChildren(children);
- NodeIterator iter = node.getNodes();
- assertThat(iter, notNullValue());
- assertThat(iter.getSize(), is(6L));
- assertThat(iter.getPosition(), is(0L));
- assertThat(iter.hasNext(), is(true));
- assertThat((Node)iter.next(), is(child1));
- assertThat(iter.getPosition(), is(1L));
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.nextNode(), is(child2_1));
- assertThat(iter.getPosition(), is(2L));
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.nextNode(), is(child2_2));
- assertThat(iter.getPosition(), is(3L));
- assertThat(iter.hasNext(), is(true));
- iter.skip(2);
- assertThat(iter.getPosition(), is(5L));
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.nextNode(), is(child5));
- assertThat(iter.getPosition(), is(6L));
- assertThat(iter.hasNext(), is(false));
- }
-
- @Test( expected = UnsupportedOperationException.class )
- public void shouldNotAllowNodeIteratorRemove() throws Exception {
- node.getNodes().remove();
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowNodeIteratorNegativeSkip() throws Exception {
- node.getNodes().skip(-1);
- }
-}
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-12 20:54:55 UTC
(rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java 2009-03-16 22:50:09 UTC
(rev 777)
@@ -25,17 +25,14 @@
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.UUID;
import javax.jcr.ItemNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.nodetype.NodeDefinition;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.jcr.SessionCache.NodeInfo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -46,56 +43,62 @@
*/
public class JcrNodeTest {
+ private UUID uuid;
private JcrNode node;
- private AbstractJcrNode root;
+ private ExecutionContext context;
@Mock
- private JcrSession session;
- @Mock
- private NodeDefinition rootNodeDefinition;
- @Mock
- private NodeDefinition nodeDefinition;
+ private SessionCache cache;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
- ExecutionContext context = new ExecutionContext();
- UUID rootUuid = UUID.randomUUID();
- Path rootPath = context.getValueFactories().getPathFactory().createRootPath();
- Location rootLocation = Location.create(rootPath, rootUuid);
- root = new JcrRootNode(session, rootLocation, rootNodeDefinition);
- UUID uuid = UUID.randomUUID();
- Path path =
context.getValueFactories().getPathFactory().create("/name[2]");
- Location location = Location.create(path, uuid);
- node = new JcrNode(session, rootUuid, location, nodeDefinition);
- stub(session.getExecutionContext()).toReturn(context);
- stub(session.getNode(rootUuid)).toReturn(root);
- stub(session.getNode(uuid)).toReturn(node);
- node.setProperties(new HashMap<Name, Property>());
- node.setChildren(new ArrayList<Location>());
+
+ uuid = UUID.randomUUID();
+ node = new JcrNode(cache, uuid);
+
+ context = new ExecutionContext();
+ stub(cache.context()).toReturn(context);
}
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path path( String path ) {
+ return context.getValueFactories().getPathFactory().create(path);
+ }
+
@Test( expected = ItemNotFoundException.class )
public void shouldNotAllowAncestorDepthGreaterThanNodeDepth() throws Exception {
- node.getAncestor(2);
+ NodeInfo info = mock(NodeInfo.class);
+ stub(cache.findNodeInfo(uuid)).toReturn(info);
+ stub(cache.getPathFor(info)).toReturn(path("/a/b/c/name[2]"));
+ node.getAncestor(6);
}
@Test
public void shouldProvideDepth() throws Exception {
- assertThat(node.getDepth(), is(1));
+ NodeInfo info = mock(NodeInfo.class);
+ stub(cache.findNodeInfo(uuid)).toReturn(info);
+ stub(cache.getPathFor(info)).toReturn(path("/a/b/c/name[2]"));
+ assertThat(node.getDepth(), is(4));
}
@Test
public void shouldProvideIndex() throws Exception {
- assertThat(node.getIndex(), is(2));
+ stub(cache.getSnsIndexOf(uuid)).toReturn(1);
+ assertThat(node.getIndex(), is(1));
}
@Test
public void shouldProvideName() throws Exception {
+ stub(cache.getNameOf(uuid)).toReturn(name("name"));
assertThat(node.getName(), is("name"));
}
@Test
public void shouldProvidePath() throws Exception {
- assertThat(node.getPath(), is("/name[2]"));
+ stub(cache.getPathFor(uuid)).toReturn(path("/a/b/c/name[2]"));
+ assertThat(node.getPath(), is("/a/b/c/name[2]"));
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java 2009-03-12
20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -32,31 +32,30 @@
import javax.jcr.PropertyIterator;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.jcr.AbstractJcrNodeTest.MockAbstractJcrNode;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
* @author jverhaeg
*/
public class JcrPropertyIteratorTest {
- private AbstractJcrNode node;
- @Mock
- private JcrSession session;
private Map<Name, Property> properties;
private ExecutionContext context;
+ private PropertyIterator iter;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
context = new ExecutionContext();
properties = new HashMap<Name, Property>();
- node = new MockAbstractJcrNode(session, "node", null);
- node.setProperties(properties);
+ properties.put(name("prop1"), Mockito.mock(Property.class));
+ properties.put(name("prop2"), Mockito.mock(Property.class));
+ properties.put(name("prop3"), Mockito.mock(Property.class));
+ properties.put(name("prop4"), Mockito.mock(Property.class));
+ iter = new JcrPropertyIterator(properties.values());
}
protected Name name( String name ) {
@@ -65,11 +64,6 @@
@Test
public void shouldProvidePropertyIterator() throws Exception {
- properties.put(name("prop1"), Mockito.mock(Property.class));
- properties.put(name("prop2"), Mockito.mock(Property.class));
- properties.put(name("prop3"), Mockito.mock(Property.class));
- properties.put(name("prop4"), Mockito.mock(Property.class));
- PropertyIterator iter = node.getProperties();
assertThat(iter, notNullValue());
assertThat(iter.getSize(), is(4L));
assertThat(iter.getPosition(), is(0L));
@@ -87,11 +81,11 @@
@Test( expected = UnsupportedOperationException.class )
public void shouldNotAllowPropertyIteratorRemove() throws Exception {
- node.getProperties().remove();
+ new JcrPropertyIterator(properties.values()).remove();
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowPropertyIteratorNegativeSkip() throws Exception {
- node.getProperties().skip(-1);
+ new JcrPropertyIterator(properties.values()).skip(-1);
}
}
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-12 20:54:55
UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java 2009-03-16 22:50:09
UTC (rev 777)
@@ -26,14 +26,10 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import java.util.HashMap;
-import java.util.Map;
+import static org.mockito.Mockito.stub;
import java.util.UUID;
import javax.jcr.ItemNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.nodetype.NodeDefinition;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.junit.Before;
@@ -46,25 +42,31 @@
*/
public class JcrRootNodeTest {
+ private UUID uuid;
private JcrRootNode root;
+ private ExecutionContext context;
@Mock
- private JcrSession session;
- @Mock
- private NodeDefinition nodeDefinition;
- private Map<Name, Property> properties;
+ private SessionCache cache;
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
- properties = new HashMap<Name, Property>();
- ExecutionContext context = new ExecutionContext();
- UUID rootUuid = UUID.randomUUID();
- Path rootPath = context.getValueFactories().getPathFactory().createRootPath();
- Location rootLocation = Location.create(rootPath, rootUuid);
- root = new JcrRootNode(session, rootLocation, nodeDefinition);
- root.setProperties(properties);
+
+ uuid = UUID.randomUUID();
+ root = new JcrRootNode(cache, uuid);
+
+ context = new ExecutionContext();
+ stub(cache.context()).toReturn(context);
}
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path path( String path ) {
+ return context.getValueFactories().getPathFactory().create(path);
+ }
+
@Test( expected = ItemNotFoundException.class )
public void shouldNotAllowAncestorDepthGreaterThanNodeDepth() throws Exception {
root.getAncestor(1);
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-03-12 20:54:55
UTC (rev 776)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-03-16 22:50:09
UTC (rev 777)
@@ -23,13 +23,13 @@
*/
package org.jboss.dna.jcr;
-import static org.junit.Assert.assertTrue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
import java.io.ByteArrayOutputStream;
@@ -71,7 +71,7 @@
public class JcrSessionTest {
private static final String MULTI_LINE_VALUE = "Line\t1\nLine 2\rLine 3\r\nLine
4";
-
+
private String workspaceName;
private ExecutionContext context;
private InMemoryRepositorySource source;
@@ -102,7 +102,7 @@
graph.set("booleanProperty").on("/a/b").to(true);
graph.set("stringProperty").on("/a/b/c").to("value");
graph.set("multiLineProperty").on("/a/b/c").to(MULTI_LINE_VALUE);
-
+
// Make sure the path to the namespaces exists ...
graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
@@ -287,13 +287,10 @@
@Test
public void shouldProvideRootNode() throws Exception {
- Map<UUID, AbstractJcrNode> nodesByUuid = session.getNodesByUuid();
- assertThat(nodesByUuid.isEmpty(), is(true));
Node root = session.getRootNode();
assertThat(root, notNullValue());
UUID uuid = ((JcrRootNode)root).internalUuid();
assertThat(uuid, notNullValue());
- assertThat(nodesByUuid.get(uuid), is(root));
}
@Test
@@ -394,14 +391,14 @@
assertThat(session.getNamespaceURI("sv"),
is("http://www.jcp.org/jcr/sv/1.0"));
// assertThat(session.getNamespaceURI("xml"),
is("http://www.w3.org/XML/1998/namespace"));
}
-
+
@Test
public void shouldExportMultiLinePropertiesInSystemView() throws Exception {
OutputStream os = new ByteArrayOutputStream();
-
+
session.exportSystemView("/a/b/c", os, false, true);
-
+
String fileContents = os.toString();
- assertTrue(fileContents.contains(MULTI_LINE_VALUE));
+ assertTrue(fileContents.contains(MULTI_LINE_VALUE));
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java
===================================================================
---
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java 2009-03-12
20:54:55 UTC (rev 776)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -31,17 +31,15 @@
import java.io.InputStream;
import java.util.UUID;
import javax.jcr.Node;
-import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.PropertyDefinition;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.jcr.SessionCache.PropertyInfo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -52,39 +50,57 @@
*/
public class JcrSingleValuePropertyTest {
- private Property prop;
- private AbstractJcrNode node;
+ private PropertyId propertyId;
+ private JcrSingleValueProperty prop;
private ExecutionContext executionContext;
+ private org.jboss.dna.graph.property.Property dnaProperty;
@Mock
+ private SessionCache cache;
+ @Mock
private JcrSession session;
@Mock
- private NodeDefinition nodeDefinition;
+ private PropertyInfo propertyInfo;
@Mock
- Name name;
+ private JcrPropertyDefinition definition;
@Mock
- private PropertyDefinition definition;
- private org.jboss.dna.graph.property.Property dnaProperty;
+ private JcrNodeTypeManager nodeTypes;
@Before
- public void before() {
+ public void before() throws Exception {
MockitoAnnotations.initMocks(this);
executionContext = new ExecutionContext();
-
- UUID rootUuid = UUID.randomUUID();
- Path rootPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
- Location rootLocation = Location.create(rootPath, rootUuid);
- node = new JcrRootNode(session, rootLocation, nodeDefinition);
+ stub(cache.session()).toReturn(session);
+ stub(cache.context()).toReturn(executionContext);
+ stub(session.nodeTypeManager()).toReturn(nodeTypes);
stub(session.getExecutionContext()).toReturn(executionContext);
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
"text/plain");
+ stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
stub(definition.isMultiple()).toReturn(false);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.STRING,
dnaProperty);
+ PropertyDefinitionId definitionId = new
PropertyDefinitionId(name("nodeTypeName"), name("propDefnName"));
+ stub(nodeTypes.getPropertyDefinition(definitionId, false)).toReturn(definition);
+
+ UUID uuid = UUID.randomUUID();
+ propertyId = new PropertyId(uuid, JcrLexicon.MIMETYPE);
+ prop = new JcrSingleValueProperty(cache, propertyId);
+
+ stub(cache.findPropertyInfo(propertyId)).toReturn(propertyInfo);
+ stub(propertyInfo.getDefinitionId()).toReturn(definitionId);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.STRING);
+ stub(propertyInfo.isMultiValued()).toReturn(false);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyName()).toReturn(dnaProperty.getName());
}
+ protected Name name( String name ) {
+ return executionContext.getValueFactories().getNameFactory().create(name);
+ }
+
@Test
public void shouldProvideBoolean() throws Exception {
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.BOOLEAN);
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
"true");
- prop = new JcrSingleValueProperty(node, definition, PropertyType.BOOLEAN,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
assertThat(prop.getBoolean(), is(true));
assertThat(prop.getType(), is(PropertyType.BOOLEAN));
}
@@ -92,7 +108,6 @@
@Test
public void shouldIndicateHasSingleValue() throws Exception {
PropertyDefinition def = prop.getDefinition();
- assertThat(def, notNullValue());
assertThat(def.isMultiple(), is(false));
}
@@ -100,7 +115,8 @@
public void shouldProvideDate() throws Exception {
DateTime dnaDate =
executionContext.getValueFactories().getDateFactory().create();
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
dnaDate);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.DATE,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.DATE);
assertThat(prop.getDate(), is(dnaDate.toCalendar()));
assertThat(prop.getLong(), is(dnaDate.getMilliseconds()));
assertThat(prop.getType(), is(PropertyType.DATE));
@@ -111,9 +127,10 @@
public void shouldProvideNode() throws Exception {
UUID referencedUuid = UUID.randomUUID();
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
referencedUuid);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.REFERENCE);
AbstractJcrNode referencedNode = mock(AbstractJcrNode.class);
- stub(session.getNode(referencedUuid)).toReturn(referencedNode);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.REFERENCE,
dnaProperty);
+ stub(cache.findJcrNode(referencedUuid)).toReturn(referencedNode);
assertThat(prop.getNode(), is((Node)referencedNode));
assertThat(prop.getType(), is(PropertyType.REFERENCE));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
@@ -122,12 +139,13 @@
@Test
public void shouldProvideDouble() throws Exception {
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
1.0);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.DOUBLE,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.DOUBLE);
assertThat(prop.getDouble(), is(1.0));
assertThat(prop.getType(), is(PropertyType.DOUBLE));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
1.0F);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.DOUBLE,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
assertThat(prop.getDouble(), is(1.0));
assertThat(prop.getType(), is(PropertyType.DOUBLE));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
@@ -136,23 +154,26 @@
@Test
public void shouldProvideLong() throws Exception {
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
1);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.DOUBLE,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.LONG);
assertThat(prop.getLong(), is(1L));
- assertThat(prop.getType(), is(PropertyType.DOUBLE));
+ assertThat(prop.getType(), is(PropertyType.LONG));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
1L);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.DOUBLE,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.LONG);
assertThat(prop.getLong(), is(1L));
assertThat(prop.getString(), is("1"));
- assertThat(prop.getType(), is(PropertyType.DOUBLE));
+ assertThat(prop.getType(), is(PropertyType.LONG));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
}
@Test
public void shouldProvideStream() throws Exception {
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
new Object());
- prop = new JcrSingleValueProperty(node, definition, PropertyType.BINARY,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.BINARY);
assertThat(prop.getType(), is(PropertyType.BINARY));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
InputStream stream = prop.getStream();
@@ -168,7 +189,8 @@
@Test
public void shouldProvideString() throws Exception {
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
"value");
- prop = new JcrSingleValueProperty(node, definition, PropertyType.STRING,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.STRING);
assertThat(prop.getString(), is("value"));
assertThat(prop.getType(), is(PropertyType.STRING));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
@@ -178,7 +200,8 @@
public void shouldAllowReferenceValue() throws Exception {
UUID uuid = UUID.randomUUID();
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
uuid);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.STRING,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.STRING);
assertThat(prop.getString(), is(uuid.toString()));
assertThat(prop.getType(), is(PropertyType.STRING));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
@@ -189,7 +212,8 @@
executionContext.getNamespaceRegistry().register("acme",
"http://example.com");
Name path =
executionContext.getValueFactories().getNameFactory().create("acme:something");
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
path);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.NAME,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.NAME);
assertThat(prop.getString(), is("acme:something"));
assertThat(prop.getType(), is(PropertyType.NAME));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
@@ -203,7 +227,8 @@
executionContext.getNamespaceRegistry().register("acme",
"http://example.com");
Path path =
executionContext.getValueFactories().getPathFactory().create("/a/b/acme:c");
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
(Object)path);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.PATH,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ stub(propertyInfo.getPropertyType()).toReturn(PropertyType.PATH);
assertThat(prop.getString(), is("/a/b/acme:c"));
assertThat(prop.getType(), is(PropertyType.PATH));
assertThat(prop.getName(),
is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
@@ -230,13 +255,13 @@
dnaValue = "some other value";
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
dnaValue);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.STRING,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
assertThat(prop.getLength(), is((long)dnaValue.length()));
Object obj = new Object();
long binaryLength =
executionContext.getValueFactories().getBinaryFactory().create(obj).getSize();
dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE,
obj);
- prop = new JcrSingleValueProperty(node, definition, PropertyType.BINARY,
dnaProperty);
+ stub(propertyInfo.getProperty()).toReturn(dnaProperty);
assertThat(prop.getLength(), is(binaryLength));
}
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
(rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-03-16
22:50:09 UTC (rev 777)
@@ -0,0 +1,480 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.stub;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import javax.jcr.nodetype.NodeType;
+import org.jboss.dna.common.statistic.Stopwatch;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+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.jcr.SessionCache.Children;
+import org.jboss.dna.jcr.SessionCache.NodeInfo;
+import org.jboss.dna.jcr.SessionCache.PropertyInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ */
+public class SessionCacheTest {
+
+ private String workspaceName;
+ private ExecutionContext context;
+ private JcrNodeTypeManager nodeTypes;
+ private Stopwatch sw;
+ private Graph store;
+ private SessionCache cache;
+ private Map<String, Graph> storesByName;
+ private Map<String, SessionCache> cachesByName;
+
+ @Mock
+ private JcrSession session;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ sw = new Stopwatch();
+ storesByName = new HashMap<String, Graph>();
+ cachesByName = new HashMap<String, SessionCache>();
+
+ context = new ExecutionContext();
+ context.getNamespaceRegistry().register("vehix",
"http://example.com/vehicles");
+
+ workspaceName = "theWorkspace";
+
+ stub(session.getExecutionContext()).toReturn(context);
+ stub(session.namespaces()).toReturn(context.getNamespaceRegistry());
+
+ // Load up all the node types ...
+ JcrNodeTypeSource nodeTypeSource = new JcrBuiltinNodeTypeSource(session);
+ nodeTypeSource = new DnaBuiltinNodeTypeSource(session, nodeTypeSource);
+ nodeTypeSource = new VehixNodeTypeSource(session, nodeTypeSource);
+ nodeTypes = new JcrNodeTypeManager(session, nodeTypeSource);
+ stub(session.nodeTypeManager()).toReturn(nodeTypes);
+
+ InMemoryRepositorySource source = new InMemoryRepositorySource();
+ source.setName("store");
+ source.setDefaultWorkspaceName(workspaceName);
+ store = Graph.create(source, context);
+
+ // Import the "cars.xml" file into the repository
+ store.importXmlFrom(new
File("src/test/resources/vehicles.xml")).into("/");
+
+ cache = new SessionCache(session, workspaceName, context, nodeTypes, store);
+ }
+
+ /**
+ * Define the node types for the "vehix" namespace.
+ */
+ public static class VehixNodeTypeSource extends AbstractJcrNodeTypeSource {
+ private final List<JcrNodeType> primaryNodeTypes;
+ private final List<JcrNodeType> mixinNodeTypes;
+
+ public VehixNodeTypeSource( JcrSession session,
+ JcrNodeTypeSource predecessor ) {
+ super(predecessor);
+ this.primaryNodeTypes = new ArrayList<JcrNodeType>();
+ this.mixinNodeTypes = new ArrayList<JcrNodeType>();
+ Name carName =
session.getExecutionContext().getValueFactories().getNameFactory().create("vehix:car");
+ Name aircraftName =
session.getExecutionContext().getValueFactories().getNameFactory().create("vehix:aircraft");
+ JcrNodeType unstructured = findType(JcrNtLexicon.UNSTRUCTURED);
+
+ // Add in the "vehix:car" node type (which extends
"nt:unstructured") ...
+ JcrNodeType car = new JcrNodeType(session, carName, Arrays.asList(new
NodeType[] {unstructured}),
+ NO_PRIMARY_ITEM_NAME, NO_CHILD_NODES,
NO_PROPERTIES, NOT_MIXIN,
+ ORDERABLE_CHILD_NODES);
+
+ // Add in the "vehix:aircraft" node type (which extends
"nt:unstructured") ...
+ JcrNodeType aircraft = new JcrNodeType(session, aircraftName,
Arrays.asList(new NodeType[] {unstructured}),
+ NO_PRIMARY_ITEM_NAME, NO_CHILD_NODES,
NO_PROPERTIES, NOT_MIXIN,
+ ORDERABLE_CHILD_NODES);
+
+ primaryNodeTypes.addAll(Arrays.asList(new JcrNodeType[] {car, aircraft,}));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.AbstractJcrNodeTypeSource#getDeclaredMixinNodeTypes()
+ */
+ @Override
+ public Collection<JcrNodeType> getDeclaredMixinNodeTypes() {
+ return mixinNodeTypes;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.jcr.AbstractJcrNodeTypeSource#getDeclaredPrimaryNodeTypes()
+ */
+ @Override
+ public Collection<JcrNodeType> getDeclaredPrimaryNodeTypes() {
+ return primaryNodeTypes;
+ }
+
+ }
+
+ protected Graph createFrom( String repositoryName,
+ String workspaceName,
+ File file ) throws IOException, SAXException {
+ InMemoryRepositorySource source = new InMemoryRepositorySource();
+ source.setName(repositoryName);
+ source.setDefaultWorkspaceName(workspaceName);
+ Graph graph = Graph.create(source, context);
+
+ if (file != null) {
+ graph.importXmlFrom(file).into("/");
+ }
+ return graph;
+ }
+
+ protected Graph getGraph( String name ) throws IOException, SAXException {
+ Graph graph = storesByName.get(name);
+ if (graph == null) {
+ graph = createFrom(name, name + " workspace", new
File("src/test/resources/" + name + ".xml"));
+ storesByName.put(name, graph);
+ }
+ return graph;
+ }
+
+ protected SessionCache getCache( String name ) throws IOException, SAXException {
+ SessionCache cache = cachesByName.get(name);
+ if (cache == null) {
+ cache = new SessionCache(session, name + " workspace", context,
nodeTypes, getGraph(name));
+ cachesByName.put(name, cache);
+ }
+ return cache;
+ }
+
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path path( String path ) {
+ return context.getValueFactories().getPathFactory().create(path);
+ }
+
+ protected Path.Segment segment( String segment ) {
+ return context.getValueFactories().getPathFactory().createSegment(segment);
+ }
+
+ protected String pad( String name ) {
+ return StringUtil.justifyLeft(name, 22, ' ');
+ }
+
+ protected void assertSameProperties( NodeInfo nodeInfo,
+ Node dnaNode ) {
+ UUID uuid = dnaNode.getLocation().getUuid();
+ assertThat(nodeInfo.getUuid(), is(uuid));
+ assertThat(nodeInfo.getOriginalLocation().getUuid(), is(uuid));
+ Set<Name> propertyNames = nodeInfo.getProperties().keySet();
+ for (Name propertyName : propertyNames) {
+ PropertyInfo info = nodeInfo.getProperty(propertyName);
+ assertThat(info.getNodeUuid(), is(uuid));
+ assertThat(info.getPropertyId().getNodeId(), is(uuid));
+ assertThat(info.getPropertyId().getPropertyName(), is(propertyName));
+ assertThat(info.getProperty().getName(), is(propertyName));
+ Property actual = dnaNode.getProperty(propertyName);
+ if (actual != null) {
+ assertThat(info.getProperty().size(), is(actual.size()));
+ assertThat(info.getProperty().getValuesAsArray(),
is(actual.getValuesAsArray()));
+ } else {
+ assertThat(propertyName, is(JcrLexicon.PRIMARY_TYPE));
+ }
+ }
+ }
+
+ @Test
+ public void shouldCreateWithValidParameters() {
+ assertThat(cache, is(notNullValue()));
+ }
+
+ @Test
+ public void shouldFindNodeInfoForRootByUuid() throws Exception {
+ Node root = store.getNodeAt("/");
+ UUID rootUuid = root.getLocation().getUuid();
+ NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
+ assertThat(rootInfo, is(notNullValue()));
+ assertThat(rootInfo.getUuid(), is(rootUuid));
+ assertThat(rootInfo.getDefinitionId().getNodeTypeName(),
is(name("dna:root")));
+ assertThat(rootInfo.getDefinitionId().getChildDefinitionName(),
is(name("*")));
+ assertThat(rootInfo.getPrimaryTypeName(), is(name("dna:root")));
+ assertThat(rootInfo.getOriginalLocation().getPath().isRoot(), is(true));
+ assertThat(rootInfo.getOriginalLocation().getUuid(), is(rootUuid));
+ Set<Name> rootProperties = rootInfo.getProperties().keySet();
+ assertThat(rootProperties, hasItems(name("jcr:primaryType")));
+ assertSameProperties(rootInfo, root);
+
+ PropertyInfo info = rootInfo.getProperty(JcrLexicon.PRIMARY_TYPE);
+ assertThat(info.getProperty().getFirstValue(),
is((Object)name("dna:root")));
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeInfoByUuid() throws Exception {
+ Node root = store.getNodeAt("/");
+ UUID rootUuid = root.getLocation().getUuid();
+ for (int i = 0; i != 20; ++i) {
+ NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
+ assertThat(rootInfo, is(notNullValue()));
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeInfoByPath() throws Exception {
+ String sourceName = "cars";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+ Node root = store.getNodeAt("/");
+ UUID rootUuid = root.getLocation().getUuid();
+ NodeInfo nodeInfo = cache.findNodeInfoForRoot();
+ assertThat(nodeInfo.getUuid(), is(rootUuid));
+ for (int i = 0; i != 20; ++i) {
+ sw.start();
+ assertThat(nodeInfo, is(sameInstance(cache.findNodeInfoForRoot())));
+ sw.stop();
+ assertThat(nodeInfo, is(sameInstance(cache.findNodeInfo(rootUuid))));
+ }
+ System.out.println(pad(sourceName) + " ==> " +
sw.getSimpleStatistics());
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeInfoByUuidFromVehiclesSource() throws
Exception {
+ String sourceName = "vehicles";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+ sw.start();
+ Node root = store.getNodeAt("/");
+ sw.stop();
+ UUID rootUuid = root.getLocation().getUuid();
+ for (int i = 0; i != 20; ++i) {
+ sw.start();
+ NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
+ sw.stop();
+ assertThat(rootInfo, is(notNullValue()));
+ }
+ System.out.println(pad(sourceName) + " ==> " +
sw.getSimpleStatistics());
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeInfoByUuidFromSourceWithPrimaryTypes() throws
Exception {
+ String sourceName = "repositoryForTckTests";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+ sw.start();
+ Node root = store.getNodeAt("/");
+ sw.stop();
+ UUID rootUuid = root.getLocation().getUuid();
+ for (int i = 0; i != 20; ++i) {
+ sw.start();
+ NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
+ sw.stop();
+ assertThat(rootInfo, is(notNullValue()));
+ }
+ System.out.println(pad(sourceName) + " ==> " +
sw.getSimpleStatistics());
+ }
+
+ @Test
+ public void shouldFindChildrenInNodeInfoForRoot() throws Exception {
+ NodeInfo root = cache.findNodeInfoForRoot();
+ Children children = root.getChildren();
+ assertThat(children, is(notNullValue()));
+ assertThat(children.size(), is(1));
+ assertThat(children.getChild(segment("vehix:Vehicles")),
is(notNullValue()));
+ }
+
+ @Test
+ public void shouldFindNodeInfoForNonRootNodeByPath() throws Exception {
+ String sourceName = "vehicles";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+ // Get the root ...
+ NodeInfo root = cache.findNodeInfoForRoot();
+
+ // Now try to load a node that is well-below the root ...
+ Path lr3Path = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land
Rover LR3");
+ Node lr3Node = store.getNodeAt(lr3Path);
+ sw.start();
+ NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
+ sw.stop();
+ assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ assertSameProperties(lr3, lr3Node);
+ System.out.println(pad(sourceName) + " ==> " +
sw.getSimpleStatistics());
+
+ // Verify that this loaded all the intermediate nodes, by walking up ...
+ NodeInfo info = lr3;
+ while (true) {
+ UUID parent = info.getParent();
+ if (parent == null) {
+ // then we should be at the root ...
+ assertThat(info.getUuid(), is(root.getUuid()));
+ break;
+ }
+ // Otherwise, we're not at the root, so we should find the parent ...
+ info = cache.findNodeInfoInCache(parent);
+ assertThat(info, is(notNullValue()));
+ }
+ }
+
+ @Test
+ public void shouldFindInfoForNodeUsingRelativePathFromRoot() throws Exception {
+ String sourceName = "vehicles";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+
+ // Verify that the node does exist in the source ...
+ Path lr3AbsolutePath =
path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ Node lr3Node = store.getNodeAt(lr3AbsolutePath);
+
+ // Get the root ...
+ NodeInfo root = cache.findNodeInfoForRoot();
+
+ // Now try to load a node that is well-below the root ...
+ Path lr3Path = path("vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land
Rover LR3");
+ assertThat(lr3Path.isAbsolute(), is(false));
+ NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
+ assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ assertSameProperties(lr3, lr3Node);
+
+ Path recoveredPath = cache.getPathFor(lr3);
+ assertThat(recoveredPath, is(lr3AbsolutePath));
+ }
+
+ @Test
+ public void shouldFindInfoForNodeUsingRelativePathFromNonRoot() throws Exception {
+ String sourceName = "vehicles";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+
+ // Verify that the node does exist in the source ...
+ Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
+ Node carsNode = store.getNodeAt(carsAbsolutePath);
+ Path lr3AbsolutePath =
path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ Node lr3Node = store.getNodeAt(lr3AbsolutePath);
+ Path b787AbsolutePath =
path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
+ Node b787Node = store.getNodeAt(b787AbsolutePath);
+
+ // Get the root ...
+ NodeInfo root = cache.findNodeInfoForRoot();
+
+ // Now try to load the cars node ...
+ Path carsPath = path("vehix:Vehicles/vehix:Cars");
+ assertThat(carsPath.isAbsolute(), is(false));
+ NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
+ assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
+ assertSameProperties(cars, carsNode);
+
+ // Now try to find the LR3 node relative to the car ...
+ Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
+ assertThat(lr3Path.isAbsolute(), is(false));
+ NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
+ assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ assertSameProperties(lr3, lr3Node);
+
+ // Now try to find the "Boeing 787" node relative to the LR3 node ...
+ Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing
787");
+ assertThat(b787Path.isAbsolute(), is(false));
+ assertThat(b787Path.isNormalized(), is(true));
+ NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
+ assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
+ assertSameProperties(b787, b787Node);
+
+ assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
+ assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
+ assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
+ }
+
+ @Test
+ public void shouldFindJcrNodeUsingAbsolutePaths() throws Exception {
+ String sourceName = "vehicles";
+ Graph store = getGraph(sourceName);
+ SessionCache cache = getCache(sourceName);
+
+ // Verify that the node does exist in the source ...
+ Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
+ Node carsNode = store.getNodeAt(carsAbsolutePath);
+ Path lr3AbsolutePath =
path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ Node lr3Node = store.getNodeAt(lr3AbsolutePath);
+ Path b787AbsolutePath =
path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
+ Node b787Node = store.getNodeAt(b787AbsolutePath);
+
+ // Get the root ...
+ NodeInfo root = cache.findNodeInfoForRoot();
+
+ // Now try to load the cars node ...
+ Path carsPath = path("vehix:Vehicles/vehix:Cars");
+ assertThat(carsPath.isAbsolute(), is(false));
+ AbstractJcrNode carJcrNode = cache.findJcrNode(root.getUuid(),
carsAbsolutePath);
+ assertThat(carJcrNode.internalUuid(), is(carsNode.getLocation().getUuid()));
+ NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
+ assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
+ assertSameProperties(cars, carsNode);
+
+ // Now try to find the LR3 node relative to the car ...
+ Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
+ assertThat(lr3Path.isAbsolute(), is(false));
+ AbstractJcrNode lr3JcrNode = cache.findJcrNode(root.getUuid(), lr3AbsolutePath);
+ assertThat(lr3JcrNode.internalUuid(), is(lr3Node.getLocation().getUuid()));
+ NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
+ assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ assertSameProperties(lr3, lr3Node);
+
+ // Now try to find the "Boeing 787" node relative to the LR3 node ...
+ Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing
787");
+ assertThat(b787Path.isAbsolute(), is(false));
+ assertThat(b787Path.isNormalized(), is(true));
+ AbstractJcrNode b787JcrNode = cache.findJcrNode(root.getUuid(),
b787AbsolutePath);
+ assertThat(b787JcrNode.internalUuid(), is(b787Node.getLocation().getUuid()));
+ NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
+ assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
+ assertSameProperties(b787, b787Node);
+
+ assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
+ assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
+ assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
+ }
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-jcr/src/test/resources/cars.xml
===================================================================
--- trunk/dna-jcr/src/test/resources/cars.xml 2009-03-12 20:54:55 UTC (rev 776)
+++ trunk/dna-jcr/src/test/resources/cars.xml 2009-03-16 22:50:09 UTC (rev 777)
@@ -45,4 +45,4 @@
<car jcr:name="Hummer H3" maker="Hummer"
model="H3" year="2008" msrp="$30,595"
userRating="3.5" valueRating="4" mpgCity="13"
mpgHighway="16" />
<car jcr:name="Ford F-150" maker="Ford"
model="F-150" year="2008" msrp="$23,910"
userRating="4" valueRating="1" mpgCity="14"
mpgHighway="20" />
</Utility>
-</Cars>\ No newline at end of file
+</Cars>
\ No newline at end of file
Added: trunk/dna-jcr/src/test/resources/vehicles.xml
===================================================================
--- trunk/dna-jcr/src/test/resources/vehicles.xml (rev 0)
+++ trunk/dna-jcr/src/test/resources/vehicles.xml 2009-03-16 22:50:09 UTC (rev 777)
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<Vehicles
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns="http://example.com/vehicles">
+ <Cars>
+ <Hybrid>
+ <car jcr:name="Toyota Prius" maker="Toyota"
model="Prius" year="2008" msrp="$21,500"
userRating="4.2" valueRating="5" mpgCity="48"
mpgHighway="45"/>
+ <car jcr:name="Toyota Highlander" maker="Toyota"
model="Highlander" year="2008" msrp="$34,200"
userRating="4" valueRating="5" mpgCity="27"
mpgHighway="25"/>
+ <car jcr:name="Nissan Altima" maker="Nissan"
model="Altima" year="2008" msrp="$18,260"
mpgCity="23" mpgHighway="32"/>
+ </Hybrid>
+ <Sports>
+ <car jcr:name="Aston Martin DB9" maker="Aston Martin"
model="DB9" year="2008" msrp="$171,600"
userRating="5" mpgCity="12" mpgHighway="19"
lengthInInches="185.5" wheelbaseInInches="108.0" engine="5,935 cc
5.9 liters V 12"/>
+ <car jcr:name="Infiniti G37" maker="Infiniti"
model="G37" year="2008" msrp="$34,900"
userRating="3.5" valueRating="4" mpgCity="18"
mpgHighway="24" />
+ </Sports>
+ <Luxury>
+ <car jcr:name="Cadillac DTS" maker="Cadillac"
model="DTS" year="2008" engine="3.6-liter V6"
userRating="0"/>
+ <car jcr:name="Bentley Continental" maker="Bentley"
model="Continental" year="2008" msrp="$170,990"
mpgCity="10" mpgHighway="17" />
+ <car jcr:name="Lexus IS350" maker="Lexus"
model="IS350" year="2008" msrp="$36,305"
mpgCity="18" mpgHighway="25" userRating="4"
valueRating="5" />
+ </Luxury>
+ <Utility>
+ <car jcr:name="Land Rover LR2" maker="Land Rover"
model="LR2" year="2008" msrp="$33,985"
userRating="4.5" valueRating="5" mpgCity="16"
mpgHighway="23" />
+ <car jcr:name="Land Rover LR3" maker="Land Rover"
model="LR3" year="2008" msrp="$48,525"
userRating="5" valueRating="2" mpgCity="12"
mpgHighway="17" />
+ <car jcr:name="Hummer H3" maker="Hummer"
model="H3" year="2008" msrp="$30,595"
userRating="3.5" valueRating="4" mpgCity="13"
mpgHighway="16" />
+ <car jcr:name="Ford F-150" maker="Ford"
model="F-150" year="2008" msrp="$23,910"
userRating="4" valueRating="1" mpgCity="14"
mpgHighway="20" />
+ </Utility>
+ </Cars>
+ <Aircraft>
+ <Business>
+ <aircraft jcr:name="Gulfstream V" maker="Gulfstream"
model="G-V" introduced="1995" range="5800nm"
cruiseSpeed="488kt" crew="2" emptyWeight="46200lb"
url="http://en.wikipedia.org/wiki/Gulfstream_V"/>
+ <aircraft jcr:name="Learjet 45" maker="Learjet"
model="LJ45" introduced="1995" numberBuilt="264+"
crew="2" emptyWeight="13695lb" range="2120nm"
cruiseSpeed="457kt"
url="http://en.wikipedia.org/wiki/Learjet_45"/>
+ </Business>
+ <Commercial>
+ <aircraft jcr:name="Boeing 777" maker="Boeing"
model="777-200LR" introduced="1995" numberBuilt="731+"
maxRange="7500nm" emptyWeight="326000lb"
cruiseSpeed="560mph"
url="http://en.wikipedia.org/wiki/Boeing_777"/>
+ <aircraft jcr:name="Boeing 767" maker="Boeing"
model="767-200" introduced="1982" numberBuilt="966+"
maxRange="3950nm" emptyWeight="176650lb"
cruiseSpeed="530mph"
url="http://en.wikipedia.org/wiki/Boeing_767"/>
+ <aircraft jcr:name="Boeing 787" maker="Boeing"
model="787-3" introduced="2009" range="3050nm"
emptyWeight="223000lb" cruiseSpeed="561mph"
url="http://en.wikipedia.org/wiki/Boeing_787"/>
+ <aircraft jcr:name="Boeing 757" maker="Boeing"
model="757-200" introduced="1983" numberBuilt="1050"
range="3900nm" maxWeight="255000lb" cruiseSpeed="530mph"
url="http://en.wikipedia.org/wiki/Boeing_757"/>
+ <aircraft jcr:name="Airbus A380" maker="Airbus"
model="A380-800" introduced="2007" numberBuilt="18"
range="8200nm" maxWeight="1235000lb" cruiseSpeed="647mph"
url="http://en.wikipedia.org/wiki/Airbus_a380"/>
+ <aircraft jcr:name="Airbus A340" maker="Airbus"
model="A340-200" introduced="1993" numberBuilt="354"
range="8000nm" maxWeight="606300lb" cruiseSpeed="557mph"
url="http://en.wikipedia.org/wiki/Airbus_A-340"/>
+ <aircraft jcr:name="Airbus A310" maker="Airbus"
model="A310-200" introduced="1983" numberBuilt="255"
cruiseSpeed="850km/h" emptyWeight="176312lb" range="3670nm"
url="http://en.wikipedia.org/wiki/Airbus_A-310"/>
+ <aircraft jcr:name="Embraer RJ-175" maker="Embraer"
model="ERJ170-200" introduced="2004" range="3334km"
cruiseSpeed="481kt" emptyWeight="21810kg"
url="http://en.wikipedia.org/wiki/EMBRAER_170"/>
+ </Commercial>
+ <Vintage>
+ <aircraft jcr:name="Fokker Trimotor" maker="Fokker"
model="F.VII" introduced="1925" cruiseSpeed="170km/h"
emptyWeight="3050kg" crew="2"
url="http://en.wikipedia.org/wiki/Fokker_trimotor"/>
+ <aircraft jcr:name="P-38 Lightning" maker="Lockheed"
model="P-38" designedBy="Kelly Johnson" introduced="1941"
numberBuilt="10037" rateOfClimb="4750ft/min" range="1300mi"
emptyWeight="12780lb" crew="1"
url="http://en.wikipedia.org/wiki/P-38_Lightning"/>
+ <aircraft jcr:name="A6M Zero" maker="Mitsubishi"
model="A6M" designedBy="Jiro Horikoshi" introduced="1940"
numberBuilt="11000" crew="1" emptyWeight="3704lb"
serviceCeiling="33000ft" maxSpeed="331mph" range="1929mi"
rateOfClimb="3100ft/min"
url="http://en.wikipedia.org/wiki/A6M_Zero"/>
+ <aircraft jcr:name="Bf 109" maker="Messerschmitt"
model="Bf 109" introduced="1937"
url="http://en.wikipedia.org/wiki/BF_109"/>
+ <aircraft jcr:name="Wright Flyer" maker="Wright
Brothers" introduced="1903" range="852ft"
maxSpeed="30mph" emptyWeight="605lb" crew="1"/>
+ </Vintage>
+ <Homebuilt>
+ <aircraft jcr:name="Long-EZ" maker="Rutan Aircraft
Factory" model="61" emptyWeight="760lb"
fuelCapacity="200L" maxSpeed="185kt" since="1976"
range="1200nm"
url="http://en.wikipedia.org/wiki/Rutan_Long-EZ"/>
+ <aircraft jcr:name="Cirrus VK-30" maker="Cirrus
Design" model="VK-30" emptyWeight="2400lb"
maxLoad="1200lb" maxSpeed="250mph" rateOfClimb="1500ft/min"
range="1300mi"
url="http://en.wikipedia.org/wiki/Cirrus_VK-30"/>
+ <aircraft jcr:name="Van's RV-4" maker="Van's
Aircraft" model="RV-4" introduced="1980"
emptyWeight="905lb" maxLoad="500lb" maxSpeed="200mph"
rateOfClimb="2450ft/min" range="725mi"
url="http://en.wikipedia.org/wiki/Van%27s_Aircraft_RV-4"/>
+ </Homebuilt>
+ </Aircraft>
+</Vehicles>
\ No newline at end of file
Property changes on: trunk/dna-jcr/src/test/resources/vehicles.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain