[dna-commits] DNA SVN: r509 - in trunk/dna-jcr/src: main/resources/org/jboss/dna/jcr and 1 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Tue Sep 9 11:18:27 EDT 2008


Author: jverhaeg at redhat.com
Date: 2008-09-09 11:18:27 -0400 (Tue, 09 Sep 2008)
New Revision: 509

Added:
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
Removed:
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.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/AbstractJcrProperty.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.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/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/JcrNodeTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.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
Log:
DNA-178: Completed implementing a read-only version of JCR over DNA.

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrItem.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -22,59 +22,80 @@
 package org.jboss.dna.jcr;
 
 import javax.jcr.Item;
+import javax.jcr.RepositoryException;
 
 /**
  * @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;
+    }
+
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Item#isModified()
      */
     public final boolean isModified() {
-        // TODO: Update when level 2
         return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Item#isNew()
      */
     public final boolean isNew() {
-        // TODO: Update when level 2
         return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @see javax.jcr.Item#isSame(javax.jcr.Item)
+     */
+    public boolean isSame( Item otherItem ) throws RepositoryException {
+        return (getSession().getWorkspace() == otherItem.getSession().getWorkspace());
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Item#refresh(boolean)
      */
     public void refresh( boolean keepChanges ) {
-        // TODO: Update when level 2
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Item#remove()
      */
     public void remove() {
-        // TODO: Update when level 2
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Item#save()
      */
     public void save() {
-        // TODO: Update when level 2
         throw new UnsupportedOperationException();
     }
 }

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -24,16 +24,17 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.UUID;
-import java.util.Map.Entry;
 import javax.jcr.Item;
+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.RepositoryException;
@@ -49,7 +50,6 @@
 import org.jboss.dna.common.util.ArgCheck;
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path.Segment;
-import org.jboss.dna.spi.graph.impl.BasicPathSegment;
 
 /**
  * @author jverhaeg
@@ -58,8 +58,9 @@
 abstract class AbstractJcrNode extends AbstractJcrItem implements Node {
 
     private final Session session;
-    private Set<Property> properties;
-    private Map<Name, Integer> childCountsByName;
+    Set<Property> properties;
+    List<Name> children;
+    List<Integer> childNameCounts;
     private UUID uuid;
 
     AbstractJcrNode( Session session ) {
@@ -70,82 +71,92 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>visitor</code> is <code>null</code>.
      * @see javax.jcr.Item#accept(javax.jcr.ItemVisitor)
      */
-    public void accept( ItemVisitor visitor ) throws RepositoryException {
+    public final void accept( ItemVisitor visitor ) throws RepositoryException {
+        ArgCheck.isNotNull(visitor, "visitor");
         visitor.visit(this);
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#addMixin(java.lang.String)
      */
-    public void addMixin( String mixinName ) {
+    public final void addMixin( String mixinName ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#addNode(java.lang.String)
      */
-    public Node addNode( String relPath ) {
+    public final Node addNode( String relPath ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#addNode(java.lang.String, java.lang.String)
      */
-    public Node addNode( String relPath,
-                         String primaryNodeTypeName ) {
+    public final Node addNode( String relPath,
+                               String primaryNodeTypeName ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Node#canAddMixin(java.lang.String)
      */
-    public boolean canAddMixin( String mixinName ) {
-        throw new UnsupportedOperationException();
+    public final boolean canAddMixin( String mixinName ) {
+        return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#cancelMerge(javax.jcr.version.Version)
      */
-    public void cancelMerge( Version version ) {
+    public final void cancelMerge( Version version ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#checkin()
      */
-    public Version checkin() {
+    public final Version checkin() {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#checkout()
      */
-    public void checkout() {
+    public final void checkout() {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#doneMerge(javax.jcr.version.Version)
      */
-    public void doneMerge( Version version ) {
+    public final void doneMerge( Version version ) {
         throw new UnsupportedOperationException();
     }
 
@@ -167,46 +178,33 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#getBaseVersion()
      */
-    public Version getBaseVersion() {
-        throw new UnsupportedOperationException();
+    public final Version getBaseVersion() throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
-    private Map<Name, Integer> getChildCountsByName() {
-        if (childCountsByName == null) {
-            childCountsByName = new HashMap<Name, Integer>();
-        }
-        return childCountsByName;
-    }
-
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getCorrespondingNodePath(java.lang.String)
      */
-    public String getCorrespondingNodePath( String workspaceName ) {
+    public final String getCorrespondingNodePath( String workspaceName ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getDefinition()
      */
     public NodeDefinition getDefinition() {
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.Node#getIndex()
-     */
-    public int getIndex() {
-        throw new UnsupportedOperationException();
-    }
-
     final UUID getInternalUuid() {
         return uuid;
     }
@@ -214,15 +212,17 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#getLock()
      */
-    public Lock getLock() {
-        throw new UnsupportedOperationException();
+    public final Lock getLock() throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getMixinNodeTypes()
      */
     public NodeType[] getMixinNodeTypes() {
@@ -232,10 +232,16 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>relativePath</code> is empty or <code>null</code>.
      * @see javax.jcr.Node#getNode(java.lang.String)
      */
-    public final Node getNode( String relativePath ) {
-        throw new UnsupportedOperationException();
+    public final Node getNode( String relativePath ) throws RepositoryException {
+        ArgCheck.isNotEmpty(relativePath, "relativePath");
+        Item item = getSession().getItem(getPath(getPath(), relativePath));
+        if (item instanceof Node) {
+            return (Node)item;
+        }
+        throw new PathNotFoundException();
     }
 
     /**
@@ -243,16 +249,76 @@
      * 
      * @see javax.jcr.Node#getNodes()
      */
-    public NodeIterator getNodes() {
-        throw new UnsupportedOperationException();
+    public final NodeIterator getNodes() {
+        return new NodeIterator() {
+
+            private final Iterator<Name> childIterator = (children == null ? null : children.iterator());
+            private final Iterator<Integer> childNameCountIterator = (childNameCounts == null ? null : childNameCounts.iterator());
+            private Name child;
+            private int childNameCount;
+            private int childNdx = 1;
+            private int ndx;
+            private Node node;
+
+            public long getPosition() {
+                return ndx;
+            }
+
+            public long getSize() {
+                return -1;
+            }
+
+            public boolean hasNext() {
+                return ((childIterator != null && childIterator.hasNext()) || (child != null && childNdx <= childNameCount));
+            }
+
+            public Object next() {
+                return nextNode();
+            }
+
+            public Node nextNode() {
+                if (childIterator == null) {
+                    throw new NoSuchElementException();
+                }
+                if (child == null || childNdx > childNameCount) {
+                    child = childIterator.next();
+                    childNameCount = childNameCountIterator.next();
+                    childNdx = 1;
+                }
+                try {
+                    node = getNode(child.getString() + '[' + childNdx + ']');
+                    childNdx++;
+                    ndx++;
+                    return node;
+                } catch (RepositoryException error) {
+                    // TODO: Change to DnaException once DNA-180 is addressed
+                    throw new RuntimeException(error);
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            public void skip( long count ) {
+                ArgCheck.isNonNegative(count, "count");
+                while (--count >= 0) {
+                    nextNode();
+                }
+            }
+        };
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getNodes(java.lang.String)
      */
     public NodeIterator getNodes( String namePattern ) {
+        // TODO: Implement after changing impl to delegate to Graph API
+        throw new UnsupportedOperationException();
+        /*
         ArgCheck.isNotEmpty(namePattern, "namePattern");
         String[] disjuncts = namePattern.split("\\|");
         List<Segment> nodes = new ArrayList<Segment>();
@@ -266,42 +332,15 @@
                 ndxPattern = pattern.substring(ndx + 1, endNdx);
                 pattern = pattern.substring(0, ndx);
             } else ndxPattern = null;
-            for (Entry<Name, Integer> entry : getChildCountsByName().entrySet()) {
-                if (entry.getKey().getString().matches(pattern)) {
-                    if (ndxPattern != null && !entry.getValue().toString().matches(ndxPattern)) continue;
-                    if (entry.getValue() > 1) nodes.add(new BasicPathSegment(entry.getKey(), entry.getValue()));
-                    else nodes.add(new BasicPathSegment(entry.getKey()));
+            for (Entry<Name, Integer> child : getChildCountsByName().entrySet()) {
+                if (child.getKey().getLocalName().matches(pattern)) {
+                    if (ndxPattern != null && !child.getValue().toString().matches(ndxPattern)) continue;
+                    if (child.getValue() > 1) nodes.add(new BasicPathSegment(child.getKey(), child.getValue()));
+                    else nodes.add(new BasicPathSegment(child.getKey()));
                 }
             }
         }
-        return new NodeIterator() {
-
-            public Node nextNode() {
-                return null;
-            }
-
-            public long getPosition() {
-                return 0;
-            }
-
-            public long getSize() {
-                return 0;
-            }
-
-            public void skip( long skipNum ) {
-            }
-
-            public boolean hasNext() {
-                return false;
-            }
-
-            public Object next() {
-                return null;
-            }
-
-            public void remove() {
-            }
-        };
+        */
     }
 
     /**
@@ -309,13 +348,20 @@
      * 
      * @see javax.jcr.Node#getPrimaryItem()
      */
-    public Item getPrimaryItem() {
-        throw new UnsupportedOperationException();
+    public final Item getPrimaryItem() throws RepositoryException {
+        // TODO: Check if declared in the node type first
+        try {
+            Property primaryItemProp = getProperty("jcr:primaryItemName");
+            return session.getItem(getPath(getPath(), primaryItemProp.getString()));
+        } catch (PathNotFoundException error) {
+            throw new ItemNotFoundException(error);
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getPrimaryNodeType()
      */
     public NodeType getPrimaryNodeType() {
@@ -327,39 +373,93 @@
      * 
      * @see javax.jcr.Node#getProperties()
      */
-    public PropertyIterator getProperties() {
-        throw new UnsupportedOperationException();
+    public final PropertyIterator getProperties() {
+        assert properties != null;
+        return new PropertyIterator() {
+
+            private final Iterator<Property> iterator = properties.iterator();
+            private int ndx;
+
+            public long getPosition() {
+                return ndx;
+            }
+
+            public long getSize() {
+                return -1;
+            }
+
+            public boolean hasNext() {
+                return iterator.hasNext();
+            }
+
+            public Object next() {
+                return nextProperty();
+            }
+
+            public Property nextProperty() {
+                Property property = iterator.next();
+                ndx++;
+                return property;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            public void skip( long count ) {
+                ArgCheck.isNonNegative(count, "count");
+                while (--count >= 0) {
+                    nextProperty();
+                }
+            }
+        };
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getProperties(java.lang.String)
      */
     public PropertyIterator getProperties( String namePattern ) {
+        // TODO: Implement after changing impl to delegate to Graph API
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>relativePath</code> is empty or <code>null</code>.
      * @see javax.jcr.Node#getProperty(java.lang.String)
      */
     public final Property getProperty( String relativePath ) throws RepositoryException {
         ArgCheck.isNotEmpty(relativePath, "relativePath");
-        // TODO: Handle multi-segment paths
+        if (relativePath.indexOf('/') >= 0) {
+            Item item = session.getItem(getPath(getPath(), relativePath));
+            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());
+        }
+        assert properties != null;
         for (Property property : properties) {
             if (relativePath.equals(property.getName())) return property;
         }
-        return null;
+        throw new PathNotFoundException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#getReferences()
      */
-    public PropertyIterator getReferences() {
+    public final PropertyIterator getReferences() {
+        // TODO: Need to provide this at the DNA layer first (probably via a connector query)
         throw new UnsupportedOperationException();
     }
 
@@ -378,12 +478,16 @@
      * @see javax.jcr.Node#getUUID()
      */
     public final String getUUID() throws RepositoryException {
-        // Check if node is referenceable
-        Property mixinsProp = getProperty("jcr:mixinTypes");
-        if (mixinsProp != null) {
-            for (Value value : mixinsProp.getValues()) {
-                if ("mix:referenceable".equals(value.getString())) return getProperty("jcr:uuid").getString();
+        // Return JCR UUID only if node is referenceable
+        try {
+            Property mixinsProp = getProperty("jcr:mixinTypes");
+            if (mixinsProp != null) {
+                for (Value value : mixinsProp.getValues()) {
+                    if ("mix:referenceable".equals(value.getString())) return getProperty("jcr:uuid").getString();
+                }
             }
+        } catch (PathNotFoundException error) {
+            throw new UnsupportedRepositoryOperationException(error);
         }
         throw new UnsupportedRepositoryOperationException();
     }
@@ -391,19 +495,40 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#getVersionHistory()
      */
-    public VersionHistory getVersionHistory() {
-        throw new UnsupportedOperationException();
+    public final VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>relativePath</code> is empty or <code>null</code>.
      * @see javax.jcr.Node#hasNode(java.lang.String)
      */
-    public boolean hasNode( String relPath ) {
-        throw new UnsupportedOperationException();
+    public final boolean hasNode( String relativePath ) throws RepositoryException {
+        ArgCheck.isNotEmpty(relativePath, "relativePath");
+        if (relativePath.indexOf('/') >= 0) {
+            return (getNode(relativePath) != null);
+        }
+        int ndxNdx = relativePath.indexOf('[');
+        String name = (ndxNdx < 0 ? relativePath : relativePath.substring(0, ndxNdx));
+        ArgCheck.isNotEmpty(name, "relativePath");
+        int childNdx = 0;
+        if (children != null) {
+            for (Name child : children) {
+                if (name.equals(child.getString())) {
+                    if (ndxNdx >= 0) {
+                        return (Integer.parseInt(relativePath.substring(ndxNdx + 1, relativePath.length() - 1)) <= childNameCounts.get(childNdx));
+                    }
+                    return true;
+                }
+                childNdx++;
+            }
+        }
+        return false;
     }
 
     /**
@@ -411,8 +536,8 @@
      * 
      * @see javax.jcr.Node#hasNodes()
      */
-    public boolean hasNodes() {
-        throw new UnsupportedOperationException();
+    public final boolean hasNodes() {
+        return (children != null && !children.isEmpty());
     }
 
     /**
@@ -420,49 +545,65 @@
      * 
      * @see javax.jcr.Node#hasProperties()
      */
-    public boolean hasProperties() {
-        throw new UnsupportedOperationException();
+    public final boolean hasProperties() {
+        assert properties != null;
+        return !properties.isEmpty();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>relativePath</code> is empty or <code>null</code>.
      * @see javax.jcr.Node#hasProperty(java.lang.String)
      */
-    public boolean hasProperty( String relPath ) {
-        throw new UnsupportedOperationException();
+    public final boolean hasProperty( String relativePath ) throws RepositoryException {
+        ArgCheck.isNotEmpty(relativePath, "relativePath");
+        if (relativePath.indexOf('/') >= 0) {
+            return (getProperty(relativePath) != null);
+        }
+        assert properties != null;
+        for (Property property : properties) {
+            if (relativePath.equals(property.getName())) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Node#holdsLock()
      */
-    public boolean holdsLock() {
-        throw new UnsupportedOperationException();
+    public final boolean holdsLock() {
+        return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Node#isCheckedOut()
      */
-    public boolean isCheckedOut() {
-        throw new UnsupportedOperationException();
+    public final boolean isCheckedOut() {
+        return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Node#isLocked()
      */
-    public boolean isLocked() {
-        throw new UnsupportedOperationException();
+    public final boolean isLocked() {
+        return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @return <code>true</code>
      * @see javax.jcr.Item#isNode()
      */
     public final boolean isNode() {
@@ -472,109 +613,137 @@
     /**
      * {@inheritDoc}
      * 
+     * @return <code>false</code>
      * @see javax.jcr.Node#isNodeType(java.lang.String)
      */
     public boolean isNodeType( String nodeTypeName ) {
-        throw new UnsupportedOperationException();
+        return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>otherItem</code> is <code>null</code>.
      * @see javax.jcr.Item#isSame(javax.jcr.Item)
      */
-    public boolean isSame( Item otherItem ) {
+    @Override
+    public final boolean isSame( Item otherItem ) throws RepositoryException {
+        ArgCheck.isNotNull(otherItem, "otherItem");
+        if (super.isSame(otherItem) && otherItem instanceof Node) {
+            if (otherItem instanceof AbstractJcrNode) {
+                return getInternalUuid().equals(((AbstractJcrNode)otherItem).getInternalUuid());
+            }
+            // If not our implementation, let the other item figure out whether we are the same.
+            return otherItem.isSame(this);
+        }
         return false;
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#lock(boolean, boolean)
      */
-    public Lock lock( boolean isDeep,
-                      boolean isSessionScoped ) {
-        throw new UnsupportedOperationException();
+    public final Lock lock( boolean isDeep,
+                            boolean isSessionScoped ) throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#merge(java.lang.String, boolean)
      */
-    public NodeIterator merge( String srcWorkspace,
-                               boolean bestEffort ) {
+    public final NodeIterator merge( String srcWorkspace,
+                                     boolean bestEffort ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#orderBefore(java.lang.String, java.lang.String)
      */
-    public void orderBefore( String srcChildRelPath,
-                             String destChildRelPath ) {
-        throw new UnsupportedOperationException();
+    public final void orderBefore( String srcChildRelPath,
+                                   String destChildRelPath ) throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#removeMixin(java.lang.String)
      */
-    public void removeMixin( String mixinName ) {
+    public final void removeMixin( String mixinName ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#restore(java.lang.String, boolean)
      */
-    public void restore( String versionName,
-                         boolean removeExisting ) {
-        throw new UnsupportedOperationException();
+    public final void restore( String versionName,
+                               boolean removeExisting ) throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#restore(javax.jcr.version.Version, boolean)
      */
-    public void restore( Version version,
-                         boolean removeExisting ) {
-        throw new UnsupportedOperationException();
+    public final void restore( Version version,
+                               boolean removeExisting ) throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#restore(javax.jcr.version.Version, java.lang.String, boolean)
      */
-    public void restore( Version version,
-                         String relPath,
-                         boolean removeExisting ) {
-        throw new UnsupportedOperationException();
+    public final void restore( Version version,
+                               String relPath,
+                               boolean removeExisting ) throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#restoreByLabel(java.lang.String, boolean)
      */
-    public void restoreByLabel( String versionLabel,
-                                boolean removeExisting ) {
-        throw new UnsupportedOperationException();
+    public final void restoreByLabel( String versionLabel,
+                                      boolean removeExisting ) throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     final void setChildren( List<Segment> children ) {
         assert children != null;
+        if (this.children == null) {
+            this.children = new ArrayList<Name>(children.size());
+            childNameCounts = new ArrayList<Integer>(children.size());
+        }
         for (Segment seg : children) {
             Name name = seg.getName();
-            Integer count = getChildCountsByName().get(name);
-            if (count == null) getChildCountsByName().put(name, 1);
-            else getChildCountsByName().put(name, count + 1);
+            int ndx = this.children.indexOf(name);
+            if (ndx >= 0) {
+                childNameCounts.set(ndx, childNameCounts.get(ndx) + 1);
+            } else {
+                this.children.add(name);
+                childNameCounts.add(1);
+            }
         }
+        assert this.children.size() == childNameCounts.size();
     }
 
     final void setInternalUuid( UUID uuid ) {
@@ -590,162 +759,178 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, boolean)
      */
-    public Property setProperty( String name,
-                                 boolean value ) {
+    public final Property setProperty( String name,
+                                       boolean value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, java.util.Calendar)
      */
-    public Property setProperty( String name,
-                                 Calendar value ) {
+    public final Property setProperty( String name,
+                                       Calendar value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, double)
      */
-    public Property setProperty( String name,
-                                 double value ) {
+    public final Property setProperty( String name,
+                                       double value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, java.io.InputStream)
      */
-    public Property setProperty( String name,
-                                 InputStream value ) {
+    public final Property setProperty( String name,
+                                       InputStream value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, long)
      */
-    public Property setProperty( String name,
-                                 long value ) {
+    public final Property setProperty( String name,
+                                       long value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Node)
      */
-    public Property setProperty( String name,
-                                 Node value ) {
+    public final Property setProperty( String name,
+                                       Node value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String)
      */
-    public Property setProperty( String name,
-                                 String value ) {
+    public final Property setProperty( String name,
+                                       String value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String, int)
      */
-    public Property setProperty( String name,
-                                 String value,
-                                 int type ) {
+    public final Property setProperty( String name,
+                                       String value,
+                                       int type ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String[])
      */
-    public Property setProperty( String name,
-                                 String[] values ) {
+    public final Property setProperty( String name,
+                                       String[] values ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String[], int)
      */
-    public Property setProperty( String name,
-                                 String[] values,
-                                 int type ) {
+    public final Property setProperty( String name,
+                                       String[] values,
+                                       int type ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value)
      */
-    public Property setProperty( String name,
-                                 Value value ) {
+    public final Property setProperty( String name,
+                                       Value value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value, int)
      */
-    public Property setProperty( String name,
-                                 Value value,
-                                 int type ) {
+    public final Property setProperty( String name,
+                                       Value value,
+                                       int type ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value[])
      */
-    public Property setProperty( String name,
-                                 Value[] values ) {
+    public final Property setProperty( String name,
+                                       Value[] values ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value[], int)
      */
-    public Property setProperty( String name,
-                                 Value[] values,
-                                 int type ) {
+    public final Property setProperty( String name,
+                                       Value[] values,
+                                       int type ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedRepositoryOperationException always
      * @see javax.jcr.Node#unlock()
      */
-    public void unlock() {
-        throw new UnsupportedOperationException();
+    public final void unlock() throws UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#update(java.lang.String)
      */
-    public void update( String srcWorkspaceName ) {
+    public final void update( String srcWorkspaceName ) {
         throw new UnsupportedOperationException();
     }
 }

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -22,18 +22,25 @@
 package org.jboss.dna.jcr;
 
 import java.io.InputStream;
+import java.io.Reader;
 import java.util.Calendar;
+import java.util.Date;
+import java.util.UUID;
 import javax.jcr.Item;
 import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
 import javax.jcr.Property;
+import javax.jcr.PropertyType;
 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.ArgCheck;
 import org.jboss.dna.spi.ExecutionContext;
 import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.ValueFactories;
 
 /**
  * @author jverhaeg
@@ -59,12 +66,27 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>visitor</code> is <code>null</code>.
      * @see javax.jcr.Item#accept(javax.jcr.ItemVisitor)
      */
-    public void accept( ItemVisitor visitor ) throws RepositoryException {
+    public final void accept( ItemVisitor visitor ) throws RepositoryException {
+        ArgCheck.isNotNull(visitor, "visitor");
         visitor.visit(this);
     }
 
+    JcrValue<?> createValue( ValueFactories valueFactories,
+                             ValueInfo valueInfo,
+                             Object value ) {
+        return createValue(valueFactories, valueInfo.valueClass, valueInfo.propertyType, value);
+    }
+
+    private <T> JcrValue<T> createValue( ValueFactories valueFactories,
+                                         Class<T> valueClass,
+                                         int propertyType,
+                                         Object value ) {
+        return new JcrValue<T>(valueFactories, propertyType, valueClass.cast(value));
+    }
+
     /**
      * {@inheritDoc}
      * 
@@ -78,12 +100,22 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#getDefinition()
      */
     public PropertyDefinition getDefinition() {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Item#getDepth()
+     */
+    public int getDepth() throws RepositoryException {
+        return getParent().getDepth() + 1;
+    }
+
     final ExecutionContext getExecutionContext() {
         return executionContext;
     }
@@ -93,7 +125,7 @@
      * 
      * @see javax.jcr.Property#getNode()
      */
-    final public Node getNode() {
+    public final Node getNode() {
         return node;
     }
 
@@ -120,8 +152,8 @@
      * 
      * @see javax.jcr.Item#getPath()
      */
-    public String getPath() throws RepositoryException {
-        return node.getPath() + '/' + getName();
+    public final String getPath() throws RepositoryException {
+        return getPath(node.getPath(), getName());
     }
 
     /**
@@ -136,6 +168,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @return false
      * @see javax.jcr.Item#isNode()
      */
     public final boolean isNode() {
@@ -147,8 +180,9 @@
      * 
      * @see javax.jcr.Item#isSame(javax.jcr.Item)
      */
-    public boolean isSame( Item otherItem ) throws RepositoryException {
-        if (otherItem instanceof Property) {
+    @Override
+    public final boolean isSame( Item otherItem ) throws RepositoryException {
+        if (super.isSame(otherItem) && otherItem instanceof Property) {
             Property otherProp = (Property)otherItem;
             return (getName().equals(otherProp.getName()) && getNode().isSame(otherProp.getNode()));
         }
@@ -158,90 +192,152 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(javax.jcr.Value)
      */
-    public void setValue( Value value ) {
+    public final void setValue( Value value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(javax.jcr.Value[])
      */
-    public void setValue( Value[] values ) {
+    public final void setValue( Value[] values ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(java.lang.String)
      */
-    public void setValue( String value ) {
+    public final void setValue( String value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(java.lang.String[])
      */
-    public void setValue( String[] values ) {
+    public final void setValue( String[] values ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(java.io.InputStream)
      */
-    public void setValue( InputStream value ) {
+    public final void setValue( InputStream value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(long)
      */
-    public void setValue( long value ) {
+    public final void setValue( long value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(double)
      */
-    public void setValue( double value ) {
+    public final void setValue( double value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(java.util.Calendar)
      */
-    public void setValue( Calendar value ) {
+    public final void setValue( Calendar value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(boolean)
      */
-    public void setValue( boolean value ) {
+    public final void setValue( boolean value ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Property#setValue(javax.jcr.Node)
      */
-    public void setValue( Node value ) {
+    public final void setValue( Node value ) {
         throw new UnsupportedOperationException();
     }
+
+    final class ValueInfo {
+
+        final Class<?> valueClass;
+        final int propertyType;
+
+        ValueInfo( Object value ) {
+            if (value instanceof Boolean) {
+                valueClass = Boolean.class;
+                propertyType = PropertyType.BOOLEAN;
+            } else if (value instanceof Date) {
+                valueClass = Date.class;
+                propertyType = PropertyType.DATE;
+            } else if (value instanceof Calendar) {
+                valueClass = Calendar.class;
+                propertyType = PropertyType.DATE;
+            } else if (value instanceof Double) {
+                valueClass = Double.class;
+                propertyType = PropertyType.DOUBLE;
+            } else if (value instanceof Float) {
+                valueClass = Float.class;
+                propertyType = PropertyType.DOUBLE;
+            } else if (value instanceof Integer) {
+                valueClass = Integer.class;
+                propertyType = PropertyType.LONG;
+            } else if (value instanceof Long) {
+                valueClass = Long.class;
+                propertyType = PropertyType.LONG;
+            } else if (value instanceof UUID) {
+                valueClass = UUID.class;
+                propertyType = PropertyType.REFERENCE;
+            } else if (value instanceof String) {
+                valueClass = String.class;
+                propertyType = PropertyType.STRING;
+            } else if (value instanceof Name) {
+                valueClass = Name.class;
+                propertyType = PropertyType.NAME;
+            } else if (value instanceof Path) {
+                valueClass = Path.class;
+                propertyType = PropertyType.PATH;
+            } else if (value instanceof InputStream) {
+                valueClass = InputStream.class;
+                propertyType = PropertyType.BINARY;
+            } else if (value instanceof Reader) {
+                valueClass = Reader.class;
+                propertyType = PropertyType.BINARY;
+            } else {
+                valueClass = Object.class;
+                propertyType = PropertyType.BINARY;
+            }
+        }
+    }
 }

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -37,6 +37,7 @@
     public static I18n inputStreamConsumed;
     public static I18n nonInputStreamConsumed;
     public static I18n pathNotFound;
+    public static I18n permissionDenied;
     public static I18n repositoryMustBeConfigured;
     public static I18n sourceInUse;
 

Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java	                        (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -0,0 +1,173 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software 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.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.ValueFactories;
+
+/**
+ * @author jverhaeg
+ */
+ at NotThreadSafe
+final class JcrMultiValueProperty extends AbstractJcrProperty {
+
+    private List<JcrValue<?>> jcrValues = new ArrayList<JcrValue<?>>();
+
+    JcrMultiValueProperty( Node node,
+                           ExecutionContext executionContext,
+                           Name name,
+                           Iterable<?> values ) {
+        super(node, executionContext, name);
+        assert values != null;
+        ValueFactories valueFactories = executionContext.getValueFactories();
+        ValueInfo valueInfo = null;
+        for (Object value : values) {
+            if (valueInfo == null) {
+                valueInfo = new ValueInfo(value);
+            }
+            jcrValues.add(createValue(valueFactories, valueInfo, value));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getBoolean()
+     */
+    public boolean getBoolean() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getDate()
+     */
+    public Calendar getDate() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getDouble()
+     */
+    public double getDouble() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getLength()
+     */
+    public long getLength() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Property#getLengths()
+     */
+    public long[] getLengths() throws RepositoryException {
+        long[] lengths = new long[jcrValues.size()];
+        Iterator<JcrValue<?>> iter = jcrValues.iterator();
+        for (int ndx = 0; iter.hasNext(); ndx++) {
+            lengths[ndx] = iter.next().getLength();
+        }
+        return lengths;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getLong()
+     */
+    public long getLong() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getStream()
+     */
+    public InputStream getStream() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getString()
+     */
+    public String getString() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Property#getType()
+     */
+    public int getType() {
+        return jcrValues.get(0).getType();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @throws ValueFormatException always
+     * @see javax.jcr.Property#getValue()
+     */
+    public Value getValue() throws ValueFormatException {
+        throw new ValueFormatException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Property#getValues()
+     */
+    public Value[] getValues() {
+        return jcrValues.toArray(new Value[jcrValues.size()]);
+    }
+}


Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -23,11 +23,10 @@
 
 import java.util.UUID;
 import javax.jcr.Node;
-import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path.Segment;
 
 /**
  * @author jverhaeg
@@ -36,16 +35,16 @@
 final class JcrNode extends AbstractJcrNode {
 
     private final UUID parentUuid;
-    private final Name name;
+    private final Segment segment;
 
     JcrNode( Session session,
              UUID parentUuid,
-             Name name ) {
+             Segment segment ) {
         super(session);
         assert parentUuid != null;
-        assert name != null;
+        assert segment != null;
         this.parentUuid = parentUuid;
-        this.name = name;
+        this.segment = segment;
     }
 
     /**
@@ -60,10 +59,19 @@
     /**
      * {@inheritDoc}
      * 
+     * @see javax.jcr.Node#getIndex()
+     */
+    public int getIndex() {
+        return segment.getIndex();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see javax.jcr.Item#getName()
      */
     public String getName() {
-        return name.getString();
+        return segment.getName().getString();
     }
 
     /**
@@ -89,10 +97,10 @@
         }
         String name = getName();
         builder.append(name);
-        NodeIterator iter = parent.getNodes(name);
-        if (iter.getSize() > 1) {
+        int ndx = getIndex();
+        if (ndx > 1) {
             builder.append('[');
-            builder.append(getIndex());
+            builder.append(ndx);
             builder.append(']');
         }
         return builder.toString();

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -22,18 +22,13 @@
 package org.jboss.dna.jcr;
 
 import java.io.InputStream;
-import java.io.Reader;
 import java.util.Calendar;
-import java.util.Date;
-import java.util.UUID;
 import javax.jcr.Node;
-import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
 import org.jboss.dna.spi.ExecutionContext;
 import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.ValueFactories;
 
 /**
@@ -50,35 +45,7 @@
         super(node, executionContext, name);
         assert value != null;
         ValueFactories valueFactories = executionContext.getValueFactories();
-        if (value instanceof Boolean) {
-            jcrValue = new JcrValue<Boolean>(valueFactories, PropertyType.BOOLEAN, (Boolean)value);
-        } else if (value instanceof Date) {
-            jcrValue = new JcrValue<Date>(valueFactories, PropertyType.DATE, (Date)value);
-        } else if (value instanceof Calendar) {
-            jcrValue = new JcrValue<Calendar>(valueFactories, PropertyType.DATE, (Calendar)value);
-        } else if (value instanceof Double) {
-            jcrValue = new JcrValue<Double>(valueFactories, PropertyType.DOUBLE, (Double)value);
-        } else if (value instanceof Float) {
-            jcrValue = new JcrValue<Float>(valueFactories, PropertyType.DOUBLE, (Float)value);
-        } else if (value instanceof Integer) {
-            jcrValue = new JcrValue<Integer>(valueFactories, PropertyType.LONG, (Integer)value);
-        } else if (value instanceof Long) {
-            jcrValue = new JcrValue<Long>(valueFactories, PropertyType.LONG, (Long)value);
-        } else if (value instanceof UUID) {
-            jcrValue = new JcrValue<UUID>(valueFactories, PropertyType.REFERENCE, (UUID)value);
-        } else if (value instanceof String) {
-            jcrValue = new JcrValue<String>(valueFactories, PropertyType.STRING, (String)value);
-        } else if (value instanceof Name) {
-            jcrValue = new JcrValue<Name>(valueFactories, PropertyType.NAME, (Name)value);
-        } else if (value instanceof Path) {
-            jcrValue = new JcrValue<Path>(valueFactories, PropertyType.PATH, (Path)value);
-        } else if (value instanceof InputStream) {
-            jcrValue = new JcrValue<InputStream>(valueFactories, PropertyType.BINARY, (InputStream)value);
-        } else if (value instanceof Reader) {
-            jcrValue = new JcrValue<Reader>(valueFactories, PropertyType.BINARY, (Reader)value);
-        } else {
-            jcrValue = new JcrValue<Object>(getExecutionContext().getValueFactories(), PropertyType.BINARY, value);
-        }
+        jcrValue = createValue(valueFactories, new ValueInfo(value), value);
     }
 
     /**
@@ -102,15 +69,6 @@
     /**
      * {@inheritDoc}
      * 
-     * @see javax.jcr.Item#getDepth()
-     */
-    public int getDepth() throws RepositoryException {
-        return getParent().getDepth() + 1;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
      * @see javax.jcr.Property#getDouble()
      */
     public double getDouble() throws RepositoryException {
@@ -129,6 +87,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws ValueFormatException always
      * @see javax.jcr.Property#getLengths()
      */
     public long[] getLengths() throws ValueFormatException {
@@ -183,65 +142,67 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws ValueFormatException always
      * @see javax.jcr.Property#getValues()
      */
     public Value[] getValues() throws ValueFormatException {
         throw new ValueFormatException();
     }
-    //
-    // /**
-    // * {@inheritDoc}
-    // *
-    // * @throws IllegalArgumentException if <code>value</code> is <code>null</code>.
-    // * @see javax.jcr.Property#setValue(javax.jcr.Value)
-    // */
-    // @SuppressWarnings( "fallthrough" )
-    // public void setValue( Value value ) throws RepositoryException {
-    // ArgCheck.isNotNull(value, "value");
-    // // TODOx: Check node type constraint
-    // try {
-    // jcrValue = JcrValue.class.cast(value);
-    // } catch (ClassCastException error) {
-    // // TODOx: not sure if this is even possible
-    // ValueFactories valueFactories = getExecutionContext().getValueFactories();
-    // int type = value.getType();
-    // switch (type) {
-    // case PropertyType.BINARY: {
-    // jcrValue = new JcrValue<InputStream>(valueFactories, type, value.getStream());
-    // break;
-    // }
-    // case PropertyType.BOOLEAN: {
-    // jcrValue = new JcrValue<Boolean>(valueFactories, type, value.getBoolean());
-    // break;
-    // }
-    // case PropertyType.DATE: {
-    // jcrValue = new JcrValue<Calendar>(valueFactories, type, value.getDate());
-    // break;
-    // }
-    // case PropertyType.DOUBLE: {
-    // jcrValue = new JcrValue<Double>(valueFactories, type, value.getDouble());
-    // break;
-    // }
-    // case PropertyType.LONG: {
-    // jcrValue = new JcrValue<Long>(valueFactories, type, value.getLong());
-    // break;
-    // }
-    // case PropertyType.REFERENCE: {
-    // try {
-    // jcrValue = new JcrValue<UUID>(valueFactories, type, UUID.fromString(value.getString()));
-    // } catch (IllegalArgumentException fallsThroughToString) {
-    // }
-    // }
-    // case PropertyType.NAME:
-    // case PropertyType.PATH:
-    // case PropertyType.STRING: {
-    // jcrValue = new JcrValue<String>(valueFactories, type, value.getString());
-    // break;
-    // }
-    // default: {
-    // throw new AssertionError("Unsupported PropertyType: " + value.getType());
-    // }
-    // }
-    // }
-    // }
+
+    /*
+     * {@inheritDoc}
+     * 
+     * @throws IllegalArgumentException if <code>value</code> is <code>null</code>.
+     * @see javax.jcr.Property#setValue(javax.jcr.Value)
+     *
+    @SuppressWarnings( "fallthrough" )
+    public void setValue( Value value ) throws RepositoryException {
+        ArgCheck.isNotNull(value, "value");
+        // TODOx: Check node type constraint
+        try {
+            jcrValue = JcrValue.class.cast(value);
+        } catch (ClassCastException error) {
+            // TODOx: not sure if this is even possible
+            ValueFactories valueFactories = getExecutionContext().getValueFactories();
+            int type = value.getType();
+            switch (type) {
+                case PropertyType.BINARY: {
+                    jcrValue = new JcrValue<InputStream>(valueFactories, type, value.getStream());
+                    break;
+                }
+                case PropertyType.BOOLEAN: {
+                    jcrValue = new JcrValue<Boolean>(valueFactories, type, value.getBoolean());
+                    break;
+                }
+                case PropertyType.DATE: {
+                    jcrValue = new JcrValue<Calendar>(valueFactories, type, value.getDate());
+                    break;
+                }
+                case PropertyType.DOUBLE: {
+                    jcrValue = new JcrValue<Double>(valueFactories, type, value.getDouble());
+                    break;
+                }
+                case PropertyType.LONG: {
+                    jcrValue = new JcrValue<Long>(valueFactories, type, value.getLong());
+                    break;
+                }
+                case PropertyType.REFERENCE: {
+                    try {
+                        jcrValue = new JcrValue<UUID>(valueFactories, type, UUID.fromString(value.getString()));
+                    } catch (IllegalArgumentException fallsThroughToString) {
+                    }
+                }
+                case PropertyType.NAME:
+                case PropertyType.PATH:
+                case PropertyType.STRING: {
+                    jcrValue = new JcrValue<String>(valueFactories, type, value.getString());
+                    break;
+                }
+                default: {
+                    throw new AssertionError("Unsupported PropertyType: " + value.getType());
+                }
+            }
+        }
+    }
+    */
 }

Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -1,114 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors. 
- *
- * This is free software; you can redistribute it and/or modify it
- * 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.
- *
- * This software 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.Iterator;
-import java.util.Set;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.common.util.ArgCheck;
-
-/**
- * @author jverhaeg
- */
- at NotThreadSafe
-class JcrPropertyIterator implements PropertyIterator {
-
-    private final Set<Property> properties;
-    private final Iterator<Property> iterator;
-    private long index = 0L;
-
-    JcrPropertyIterator( Set<Property> properties ) {
-        assert properties != null;
-        this.properties = properties;
-        iterator = properties.iterator();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.PropertyIterator#nextProperty()
-     */
-    public Property nextProperty() {
-        Property property = iterator.next();
-        index++;
-        return property;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.RangeIterator#getPosition()
-     */
-    public long getPosition() {
-        return index;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.RangeIterator#getSize()
-     */
-    public long getSize() {
-        return properties.size();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.RangeIterator#skip(long)
-     */
-    public void skip( long count ) {
-        ArgCheck.isNonNegative(count, "count");
-        while (--count >= 0) {
-            iterator.next();
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.util.Iterator#hasNext()
-     */
-    public boolean hasNext() {
-        return iterator.hasNext();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.util.Iterator#next()
-     */
-    public Object next() {
-        return nextProperty();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.util.Iterator#remove()
-     */
-    public void remove() {
-        iterator.remove();
-    }
-}

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -113,22 +113,15 @@
         }
         // Initialize required JCR descriptors.
         modifiableDescriptors.put(Repository.LEVEL_1_SUPPORTED, "true");
-        // TODO: Change to true once level 2 supported
         modifiableDescriptors.put(Repository.LEVEL_2_SUPPORTED, "false");
-        // TODO: Change to true once locking supported
         modifiableDescriptors.put(Repository.OPTION_LOCKING_SUPPORTED, "false");
-        // TODO: Change to true once observation supported
         modifiableDescriptors.put(Repository.OPTION_OBSERVATION_SUPPORTED, "false");
-        // TODO: Change to true once query SQL supported
         modifiableDescriptors.put(Repository.OPTION_QUERY_SQL_SUPPORTED, "false");
-        // TODO: Change to true once transactions supported
         modifiableDescriptors.put(Repository.OPTION_TRANSACTIONS_SUPPORTED, "false");
-        // TODO: Change to true once versioning supported
         modifiableDescriptors.put(Repository.OPTION_VERSIONING_SUPPORTED, "false");
         modifiableDescriptors.put(Repository.QUERY_XPATH_DOC_ORDER, "true");
         modifiableDescriptors.put(Repository.QUERY_XPATH_POS_INDEX, "true");
         // Vendor-specific descriptors (REP_XXX) will only be initialized if not already present, allowing for customer branding.
-        // TODO: Should allow for branding via configuration
         if (!modifiableDescriptors.containsKey(Repository.REP_NAME_DESC)) {
             modifiableDescriptors.put(Repository.REP_NAME_DESC, JcrI18n.REP_NAME_DESC.text());
         }
@@ -139,7 +132,6 @@
             modifiableDescriptors.put(Repository.REP_VENDOR_URL_DESC, "http://www.jboss.org/dna");
         }
         if (!modifiableDescriptors.containsKey(Repository.REP_VERSION_DESC)) {
-            // TODO: Permanent to-do to update the version for each release
             modifiableDescriptors.put(Repository.REP_VERSION_DESC, "0.2");
         }
         modifiableDescriptors.put(Repository.SPEC_NAME_DESC, JcrI18n.SPEC_NAME_DESC.text());
@@ -150,9 +142,11 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>key</code> is <code>null</code>.
      * @see javax.jcr.Repository#getDescriptor(java.lang.String)
      */
     public String getDescriptor( String key ) {
+        ArgCheck.isNotEmpty(key, "key");
         return descriptors.get(key);
     }
 
@@ -195,6 +189,16 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>credentials</code> is not <code>null</code> but:
+     *         <ul>
+     *         <li>provides neither a <code>getLoginContext()</code> nor a <code>getAccessControlContext()</code> method.</li>
+     *         <li>provides a <code>getLoginContext()</code> method that doesn't return a {@link LoginContext}.
+     *         <li>provides a <code>getLoginContext()</code> method that returns a <code>null</code> {@link LoginContext}.
+     *         <li>does not provide a <code>getLoginContext()</code> method, but provides a <code>getAccessControlContext()</code>
+     *         method that doesn't return an {@link AccessControlContext}.
+     *         <li>does not provide a <code>getLoginContext()</code> method, but provides a <code>getAccessControlContext()</code>
+     *         method that returns a <code>null</code> {@link AccessControlContext}.
+     *         </ul>
      * @see javax.jcr.Repository#login(javax.jcr.Credentials, java.lang.String)
      */
     public synchronized Session login( Credentials credentials,

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -39,6 +39,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @return 0;
      * @see javax.jcr.Item#getDepth()
      */
     public int getDepth() {
@@ -48,6 +49,17 @@
     /**
      * {@inheritDoc}
      * 
+     * @return 1;
+     * @see javax.jcr.Node#getIndex()
+     */
+    public int getIndex() {
+        return 1;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @return "";
      * @see javax.jcr.Item#getName()
      */
     public String getName() {
@@ -57,6 +69,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws ItemNotFoundException always
      * @see javax.jcr.Item#getParent()
      */
     public Node getParent() throws ItemNotFoundException {
@@ -66,6 +79,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @return "/";
      * @see javax.jcr.Item#getPath()
      */
     public String getPath() {

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -24,19 +24,24 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
+import java.security.AccessControlException;
 import java.security.Principal;
+import java.util.Calendar;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import java.util.WeakHashMap;
 import javax.jcr.Credentials;
 import javax.jcr.Item;
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.Property;
+import javax.jcr.PropertyType;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.Workspace;
 import javax.security.auth.Subject;
@@ -50,6 +55,7 @@
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.UuidFactory;
+import org.jboss.dna.spi.graph.ValueFactories;
 import org.jboss.dna.spi.graph.Path.Segment;
 import org.jboss.dna.spi.graph.commands.GraphCommand;
 import org.jboss.dna.spi.graph.commands.impl.BasicGetNodeCommand;
@@ -66,6 +72,7 @@
     private final ExecutionContext executionContext;
     private RepositoryConnection connection;
     private final Map<UUID, WeakReference<Node>> nodesByUuid;
+    private final Map<String, WeakReference<Node>> nodesByJcrUuid;
     private boolean isLive;
     private Workspace workspace;
     private JcrRootNode rootNode;
@@ -84,6 +91,7 @@
         this.executionContext = executionContext;
         this.connection = connection;
         this.nodesByUuid = nodesByUuid;
+        this.nodesByJcrUuid = new WeakHashMap<String, WeakReference<Node>>();
         this.isLive = true;
         // Following must be initialized after session's state is initialized
         this.workspace = new JcrWorkspace(this, workspaceName);
@@ -92,6 +100,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#addLockToken(java.lang.String)
      */
     public void addLockToken( String lt ) {
@@ -101,11 +110,16 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if either <code>path</code> or <code>actions</code> is empty or <code>null</code>.
      * @see javax.jcr.Session#checkPermission(java.lang.String, java.lang.String)
      */
-    public void checkPermission( String absPath,
+    public void checkPermission( String path,
                                  String actions ) {
-        throw new UnsupportedOperationException();
+        ArgCheck.isNotEmpty(path, "path");
+        ArgCheck.isNotEmpty(actions, "actions");
+        if (!"read".equals(actions)) {
+            throw new AccessControlException(JcrI18n.permissionDenied.text(path, actions));
+        }
     }
 
     private void execute( GraphCommand... commands ) throws RepositoryException {
@@ -121,6 +135,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#exportDocumentView(java.lang.String, org.xml.sax.ContentHandler, boolean, boolean)
      */
     public void exportDocumentView( String absPath,
@@ -133,6 +148,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#exportDocumentView(java.lang.String, java.io.OutputStream, boolean, boolean)
      */
     public void exportDocumentView( String absPath,
@@ -145,6 +161,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#exportSystemView(java.lang.String, org.xml.sax.ContentHandler, boolean, boolean)
      */
     public void exportSystemView( String absPath,
@@ -157,6 +174,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#exportSystemView(java.lang.String, java.io.OutputStream, boolean, boolean)
      */
     public void exportSystemView( String absPath,
@@ -169,6 +187,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @return <code>null</code>
      * @see javax.jcr.Session#getAttribute(java.lang.String)
      */
     public Object getAttribute( String name ) {
@@ -178,6 +197,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @return An empty array
      * @see javax.jcr.Session#getAttributeNames()
      */
     public String[] getAttributeNames() {
@@ -187,6 +207,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getImportContentHandler(java.lang.String, int)
      */
     public ContentHandler getImportContentHandler( String parentAbsPath,
@@ -197,6 +218,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>absolutePath</code> is empty or <code>null</code>.
      * @see javax.jcr.Session#getItem(java.lang.String)
      */
     public Item getItem( String absolutePath ) throws RepositoryException {
@@ -230,6 +252,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getLockTokens()
      */
     public String[] getLockTokens() {
@@ -239,6 +262,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getNamespacePrefix(java.lang.String)
      */
     public String getNamespacePrefix( String uri ) {
@@ -248,6 +272,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getNamespacePrefixes()
      */
     public String[] getNamespacePrefixes() {
@@ -257,6 +282,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getNamespaceURI(java.lang.String)
      */
     public String getNamespaceURI( String prefix ) {
@@ -283,9 +309,8 @@
         // If not create a new one & populate it
         JcrNode node;
         Path parentPath = path.getParent();
-        if (parentPath.isRoot()) node = new JcrNode(this, ((JcrRootNode)getRootNode()).getInternalUuid(),
-                                                    path.getLastSegment().getName());
-        else node = new JcrNode(this, ((JcrNode)getNode(parentPath)).getInternalUuid(), path.getLastSegment().getName());
+        if (parentPath.isRoot()) node = new JcrNode(this, ((JcrRootNode)getRootNode()).getInternalUuid(), path.getLastSegment());
+        else node = new JcrNode(this, ((JcrNode)getNode(parentPath)).getInternalUuid(), path.getLastSegment());
         populateNode(node, command);
         return node;
     }
@@ -293,9 +318,11 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getNodeByUUID(java.lang.String)
      */
     public Node getNodeByUUID( String uuid ) {
+        // TODO: Need DNA command to get node by UUID before implementing
         throw new UnsupportedOperationException();
     }
 
@@ -349,7 +376,42 @@
      * @see javax.jcr.Session#getValueFactory()
      */
     public ValueFactory getValueFactory() {
-        throw new UnsupportedOperationException();
+        final ValueFactories valueFactories = executionContext.getValueFactories();
+        return new ValueFactory() {
+
+            public Value createValue( String value,
+                                      int propertyType ) {
+                return new JcrValue<String>(valueFactories, propertyType, value);
+            }
+
+            public Value createValue( Node value ) throws RepositoryException {
+                return new JcrValue<UUID>(valueFactories, PropertyType.REFERENCE, UUID.fromString(value.getUUID()));
+            }
+
+            public Value createValue( InputStream value ) {
+                return new JcrValue<InputStream>(valueFactories, PropertyType.BINARY, value);
+            }
+
+            public Value createValue( Calendar value ) {
+                return new JcrValue<Calendar>(valueFactories, PropertyType.DATE, value);
+            }
+
+            public Value createValue( boolean value ) {
+                return new JcrValue<Boolean>(valueFactories, PropertyType.BOOLEAN, value);
+            }
+
+            public Value createValue( double value ) {
+                return new JcrValue<Double>(valueFactories, PropertyType.DOUBLE, value);
+            }
+
+            public Value createValue( long value ) {
+                return new JcrValue<Long>(valueFactories, PropertyType.LONG, value);
+            }
+
+            public Value createValue( String value ) {
+                return new JcrValue<String>(valueFactories, PropertyType.STRING, value);
+            }
+        };
     }
 
     /**
@@ -364,10 +426,11 @@
     /**
      * {@inheritDoc}
      * 
+     * @return false
      * @see javax.jcr.Session#hasPendingChanges()
      */
     public boolean hasPendingChanges() {
-        throw new UnsupportedOperationException();
+        return false;
     }
 
     /**
@@ -375,13 +438,14 @@
      * 
      * @see javax.jcr.Session#impersonate(javax.jcr.Credentials)
      */
-    public Session impersonate( Credentials credentials ) {
-        throw new UnsupportedOperationException();
+    public Session impersonate( Credentials credentials ) throws RepositoryException {
+        return repository.login(credentials);
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#importXML(java.lang.String, java.io.InputStream, int)
      */
     public void importXML( String parentAbsPath,
@@ -402,10 +466,11 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws IllegalArgumentException if <code>absolutePath</code> is empty or <code>null</code>.
      * @see javax.jcr.Session#itemExists(java.lang.String)
      */
-    public boolean itemExists( String absPath ) {
-        throw new UnsupportedOperationException();
+    public boolean itemExists( String absolutePath ) throws RepositoryException {
+        return (getItem(absolutePath) != null);
     }
 
     /**
@@ -426,12 +491,14 @@
             executionContext.getLoginContext().logout();
             isLive = false;
         } catch (LoginException error) {
+            // TODO; Log error
         }
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#move(java.lang.String, java.lang.String)
      */
     public void move( String srcAbsPath,
@@ -454,22 +521,27 @@
         for (org.jboss.dna.spi.graph.Property dnaProp : getNodeCommand.getProperties()) {
             Name name = dnaProp.getName();
             if (uuid == null && DnaLexicon.UUID.equals(name)) uuid = uuidFactory.create(dnaProp.getValues()).next();
+            else if (dnaProp.isMultiple()) properties.add(new JcrMultiValueProperty(node, executionContext, name, dnaProp));
             else {
-                if (jcrUuidName.equals(name)) uuid = uuidFactory.create(dnaProp.getValues()).next();
-                properties.add(new JcrProperty(node, executionContext, name, dnaProp.getValues().next()));
+                if (jcrUuidName.equals(name)) {
+                    uuid = uuidFactory.create(dnaProp.getValues()).next();
+                    nodesByJcrUuid.put(uuid.toString(), new WeakReference<Node>(node));
+                } else properties.add(new JcrProperty(node, executionContext, name, dnaProp.getValues().next()));
             }
+
         }
         node.setProperties(properties);
         // Set node's UUID, creating one if necessary
         if (uuid == null) uuid = UUID.randomUUID();
         node.setInternalUuid(uuid);
         // Setup node to be retrieved by DNA UUID
-        nodesByUuid.put(node.getInternalUuid(), new WeakReference<Node>(node));
+        nodesByUuid.put(new UUID(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()), new WeakReference<Node>(node));
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#refresh(boolean)
      */
     public void refresh( boolean keepChanges ) {
@@ -479,6 +551,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#removeLockToken(java.lang.String)
      */
     public void removeLockToken( String lt ) {
@@ -488,6 +561,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#save()
      */
     public void save() {
@@ -497,6 +571,7 @@
     /**
      * {@inheritDoc}
      * 
+     * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#setNamespacePrefix(java.lang.String, java.lang.String)
      */
     public void setNamespacePrefix( String newPrefix,

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2008-09-09 15:18:27 UTC (rev 509)
@@ -27,6 +27,7 @@
 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}
+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.
 

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrItemTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -71,10 +71,6 @@
             public boolean isNode() {
                 return false;
             }
-
-            public boolean isSame( Item otherItem ) {
-                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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -22,16 +22,32 @@
 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.io.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 import javax.jcr.Item;
+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.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.Workspace;
+import javax.jcr.version.Version;
+import org.jboss.dna.spi.graph.Path.Segment;
+import org.jboss.dna.spi.graph.impl.BasicName;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -46,30 +62,15 @@
     private AbstractJcrNode node;
     @Mock
     private Session session;
+    private List<Segment> children;
     private Set<Property> properties;
 
     @Before
-    public void before() {
+    public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
+        children = new ArrayList<Segment>();
         properties = new HashSet<Property>();
-        node = new AbstractJcrNode(session) {
-
-            public int getDepth() {
-                return 0;
-            }
-
-            public String getName() {
-                return null;
-            }
-
-            public Node getParent() {
-                return null;
-            }
-
-            public String getPath() {
-                return null;
-            }
-        };
+        node = new MockAbstractJcrNode(session, "node", null);
         node.setProperties(properties);
     }
 
@@ -80,26 +81,14 @@
         Mockito.verify(visitor).visit(node);
     }
 
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowVisitationIfNoVisitor() throws Exception {
+        node.accept(null);
+    }
+
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNoSession() throws Exception {
-        new AbstractJcrNode(null) {
-
-            public int getDepth() {
-                return 0;
-            }
-
-            public String getName() {
-                return null;
-            }
-
-            public Node getParent() {
-                return null;
-            }
-
-            public String getPath() {
-                return null;
-            }
-        };
+        new MockAbstractJcrNode(null, null, null);
     }
 
     @Test( expected = IllegalArgumentException.class )
@@ -113,11 +102,6 @@
     }
 
     @Test
-    public void shouldProvideSession() throws Exception {
-        assertThat(node.getSession(), is(session));
-    }
-
-    @Test
     public void shouldProvideInternalUuid() throws Exception {
         UUID uuid = UUID.randomUUID();
         node.setInternalUuid(uuid);
@@ -132,8 +116,563 @@
         assertThat(node.getProperty("test"), is(property));
     }
 
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowAddMixin() throws Exception {
+        node.addMixin(null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowAddNode() throws Exception {
+        node.addNode(null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowAddNodeWithType() throws Exception {
+        node.addNode(null, null);
+    }
+
     @Test
-    public void shouldBeANode() {
+    public void shoudNotAllowCanAddMixin() throws Exception {
+        assertThat(node.canAddMixin(null), is(false));
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowCancelMerge() throws Exception {
+        node.cancelMerge(null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowCheckin() throws Exception {
+        node.checkin();
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowCheckout() throws Exception {
+        node.checkout();
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shoudNotAllowDoneMerge() throws Exception {
+        node.doneMerge(null);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shoudNotAllowGetBaseVersion() throws Exception {
+        node.getBaseVersion();
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowGetCorrespondingNodePath() throws Exception {
+        node.getCorrespondingNodePath(null);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shoudNotAllowGetLock() throws Exception {
+        node.getLock();
+    }
+
+    @Test
+    public void shouldProvideNode() throws Exception {
+        Node child = createChild("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 shouldNotAllowGetNodeWithNoPath() throws Exception {
+        node.getNode(null);
+    }
+
+    @Test( expected = PathNotFoundException.class )
+    public void shouldNotProvideNodeIfPathNotFound() throws Exception {
+        node.getNode("bogus");
+    }
+
+    @Test( expected = PathNotFoundException.class )
+    public void shouldNotProvideNodeIfPathIsProperty() throws Exception {
+        Property property = Mockito.mock(Property.class);
+        stub(session.getItem("/property")).toReturn(property);
+        node.getNode("property");
+    }
+
+    @Test
+    public void shouldProvideNodeIterator() throws Exception {
+        Node child1 = createChild("child1", 1, children, node);
+        Node child2_1 = createChild("child2", 1, children, node);
+        Node child2_2 = createChild("child2", 2, children, node);
+        createChild("child3", 1, children, node);
+        createChild("child4", 1, children, node);
+        Node child5 = createChild("child5", 1, children, node);
+        node.setChildren(children);
+        NodeIterator iter = node.getNodes();
+        assertThat(iter, notNullValue());
+        assertThat(iter.getSize(), is(-1L));
+        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);
+    }
+
+    @Test
+    public void shoudProvidePrimaryItem() throws Exception {
+        Property property = Mockito.mock(Property.class);
+        stub(property.getName()).toReturn("jcr:primaryItemName");
+        stub(property.getString()).toReturn("primaryItem");
+        properties.add(property);
+        Item primaryItem = Mockito.mock(Item.class);
+        stub(session.getItem("/node/primaryItem")).toReturn(primaryItem);
+        assertThat(node.getPrimaryItem(), is(primaryItem));
+    }
+
+    @Test( expected = ItemNotFoundException.class )
+    public void shoudNotProvidePrimaryItemIfUnavailable() throws Exception {
+        node.getPrimaryItem();
+    }
+
+    @Test
+    public void shouldProvidePropertyIterator() throws Exception {
+        properties.add(Mockito.mock(Property.class));
+        properties.add(Mockito.mock(Property.class));
+        properties.add(Mockito.mock(Property.class));
+        properties.add(Mockito.mock(Property.class));
+        PropertyIterator iter = node.getProperties();
+        assertThat(iter, notNullValue());
+        assertThat(iter.getSize(), is(-1L));
+        assertThat(iter.getPosition(), is(0L));
+        assertThat(iter.hasNext(), is(true));
+        assertThat(iter.next(), notNullValue());
+        assertThat(iter.getPosition(), is(1L));
+        assertThat(iter.hasNext(), is(true));
+        iter.skip(2);
+        assertThat(iter.getPosition(), is(3L));
+        assertThat(iter.hasNext(), is(true));
+        assertThat(iter.nextProperty(), notNullValue());
+        assertThat(iter.getPosition(), is(4L));
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowPropertyIteratorRemove() throws Exception {
+        node.getProperties().remove();
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowPropertyIteratorNegativeSkip() throws Exception {
+        node.getProperties().skip(-1);
+    }
+
+    @Test
+    public void shouldProvideProperty() throws Exception {
+        Property prop1 = Mockito.mock(Property.class);
+        stub(prop1.getName()).toReturn("prop1");
+        properties.add(prop1);
+        assertThat(node.getProperty("prop1"), is(prop1));
+        MockAbstractJcrNode child = createChild("child", 1, children, node);
+        Set<Property> properties = new HashSet<Property>();
+        child.setProperties(properties);
+        Property prop2 = Mockito.mock(Property.class);
+        stub(prop2.getName()).toReturn("prop2");
+        stub(session.getItem("/node/child/prop2")).toReturn(prop2);
+        properties.add(prop2);
+        MockAbstractJcrNode prop3Node = createChild("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.add(prop3);
+        stub(session.getItem("/node/child/prop3")).toReturn(prop3Node);
+        assertThat(node.getProperty("child/prop3"), is(prop3));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowGetPropertyWithNullPath() throws Exception {
+        node.getProperty(null);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowGetPropertyWithEmptyPath() throws Exception {
+        node.getProperty("");
+    }
+
+    @Test( expected = PathNotFoundException.class )
+    public void shouldNotProvideChildPropertyIfNotAvailable() throws Exception {
+        node.getProperty("prop1");
+    }
+
+    @Test( expected = PathNotFoundException.class )
+    public void shouldNotProvideDescendentPropertyIfNotAvailable() throws Exception {
+        MockAbstractJcrNode child = createChild("child", 1, children, node);
+        Set<Property> properties = new HashSet<Property>();
+        child.setProperties(properties);
+        MockAbstractJcrNode propNode = createChild("prop", 1, children, child);
+        node.setChildren(children);
+        stub(session.getItem("/node/child/prop")).toReturn(propNode);
+        node.getProperty("child/prop");
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowGetReferences() throws Exception {
+        node.getReferences();
+    }
+
+    @Test
+    public void shouldProvideSession() throws Exception {
+        assertThat(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.add(mixinProp);
+        Property uuidProp = Mockito.mock(Property.class);
+        stub(uuidProp.getName()).toReturn("jcr:uuid");
+        stub(uuidProp.getString()).toReturn(uuid);
+        properties.add(uuidProp);
+        assertThat(node.getUUID(), is(uuid));
+    }
+
+    @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.add(mixinProp);
+        Property uuidProp = Mockito.mock(Property.class);
+        stub(uuidProp.getName()).toReturn("jcr:uuid");
+        stub(uuidProp.getString()).toReturn(uuid);
+        properties.add(uuidProp);
+        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.add(uuidProp);
+        node.getUUID();
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowGetVersionHistory() throws Exception {
+        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.add(prop);
+        assertThat(node.hasNode("prop"), is(false));
+        Node child = createChild("child", 1, children, node);
+        Node child2 = createChild("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
+    public void shouldNotIndicateHasNodeIfPathIsChildProperty() throws Exception {
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowHasNodeWithNoPath() throws Exception {
+        node.hasNode(null);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowHasNodeWithEmptyPath() throws Exception {
+        node.hasNode("");
+    }
+
+    @Test
+    public void shouldProvideHasNodes() throws Exception {
+        assertThat(node.hasNodes(), is(false));
+        createChild("child", 1, children, node);
+        node.setChildren(children);
+        assertThat(node.hasNodes(), is(true));
+    }
+
+    @Test
+    public void shouldProvideHasProperties() throws Exception {
+        assertThat(node.hasProperties(), is(false));
+        properties.add(Mockito.mock(Property.class));
+        assertThat(node.hasProperties(), is(true));
+    }
+
+    @Test
+    public void shouldIndicateHasProperty() throws Exception {
+        assertThat(node.hasProperty("prop"), is(false));
+        MockAbstractJcrNode child = createChild("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.add(prop);
+        assertThat(node.hasProperty("prop"), is(true));
+        Set<Property> properties = new HashSet<Property>();
+        child.setProperties(properties);
+        Property prop2 = Mockito.mock(Property.class);
+        stub(prop2.getName()).toReturn("prop2");
+        properties.add(prop2);
+        stub(session.getItem("/node/child/prop2")).toReturn(prop2);
+        assertThat(node.hasProperty("child/prop2"), is(true));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowHasPropertyWithNoPath() throws Exception {
+        node.hasProperty(null);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowHasPropertyWithEmptyPath() throws Exception {
+        node.hasProperty("");
+    }
+
+    @Test
+    public void shouldNotAllowHoldsLock() throws Exception {
+        assertThat(node.holdsLock(), is(false));
+    }
+
+    @Test
+    public void shouldNotAllowIsCheckedOut() throws Exception {
+        assertThat(node.isCheckedOut(), is(false));
+    }
+
+    @Test
+    public void shouldNotAllowIsLocked() throws Exception {
+        assertThat(node.isLocked(), is(false));
+    }
+
+    @Test
+    public void shouldIndicateIsNode() {
         assertThat(node.isNode(), is(true));
     }
+
+    @Test
+    public void shouldProvideIsSame() throws Exception {
+        stub(session.getWorkspace()).toReturn(Mockito.mock(Workspace.class));
+        Session session2 = Mockito.mock(Session.class);
+        Node node2 = new MockAbstractJcrNode(session2, node.getName(), node.getParent());
+        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);
+        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());
+        assertThat(node.isSame(node2), is(false));
+        ((MockAbstractJcrNode)node2).setInternalUuid(uuid);
+        assertThat(node.isSame(node2), is(true));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowIsSameWithNoItem() throws Exception {
+        node.isSame(null);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowLock() throws Exception {
+        node.lock(false, false);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowMerge() throws Exception {
+        node.merge(null, false);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowOrderBefore() throws Exception {
+        node.orderBefore(null, null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowRemoveMixin() throws Exception {
+        node.removeMixin(null);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowRestoreVersionName() throws Exception {
+        node.restore((String)null, false);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowRestoreVersion() throws Exception {
+        node.restore((Version)null, false);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowRestoreVersionAtPath() throws Exception {
+        node.restore(null, null, false);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowRestoreByLabel() throws Exception {
+        node.restoreByLabel(null, false);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetBooleanProperty() throws Exception {
+        node.setProperty(null, false);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetCalendarProperty() throws Exception {
+        node.setProperty(null, (Calendar)null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetDoubleProperty() throws Exception {
+        node.setProperty(null, 0.0);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetInputStreamProperty() throws Exception {
+        node.setProperty(null, (InputStream)null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetLongProperty() throws Exception {
+        node.setProperty(null, 0L);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetNodeProperty() throws Exception {
+        node.setProperty(null, (Node)null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetStringProperty() throws Exception {
+        node.setProperty(null, (String)null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetStringsProperty() throws Exception {
+        node.setProperty(null, (String[])null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetValueProperty() throws Exception {
+        node.setProperty(null, (Value)null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetValuesProperty() throws Exception {
+        node.setProperty(null, (Value[])null);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetStringPropertyWithType() throws Exception {
+        node.setProperty(null, (String)null, 0);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetStringsPropertyWithType() throws Exception {
+        node.setProperty(null, (String[])null, 0);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetValuePropertyWithType() throws Exception {
+        node.setProperty(null, (Value)null, 0);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetValuesPropertyWithType() throws Exception {
+        node.setProperty(null, (Value[])null, 0);
+    }
+
+    @Test( expected = UnsupportedRepositoryOperationException.class )
+    public void shouldNotAllowUnlock() throws Exception {
+        node.unlock();
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowUpdate() throws Exception {
+        node.update(null);
+    }
+
+    private MockAbstractJcrNode createChild( String name,
+                                             int index,
+                                             List<Segment> children,
+                                             Node parent ) throws Exception {
+        MockAbstractJcrNode child = new MockAbstractJcrNode(session, name, parent);
+        Segment seg = Mockito.mock(Segment.class);
+        stub(seg.getName()).toReturn(new BasicName(null, name));
+        children.add(seg);
+        stub(session.getItem(parent.getPath() + "/{}" + name + '[' + index + ']')).toReturn(child);
+        return child;
+    }
+
+    private class MockAbstractJcrNode extends AbstractJcrNode {
+
+        String name;
+        Node parent;
+
+        MockAbstractJcrNode( Session session,
+                             String name,
+                             Node parent ) {
+            super(session);
+            this.name = name;
+            this.parent = parent;
+        }
+
+        public int getDepth() {
+            return 0;
+        }
+
+        public int getIndex() {
+            return 0;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Node getParent() {
+            return parent;
+        }
+
+        public String getPath() throws RepositoryException {
+            return (parent == null ? '/' + getName() : parent.getPath() + '/' + getName());
+        }
+    }
 }

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -33,6 +33,7 @@
 import javax.jcr.Property;
 import javax.jcr.Session;
 import javax.jcr.Value;
+import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.spi.ExecutionContext;
 import org.jboss.dna.spi.graph.Name;
 import org.junit.Before;
@@ -48,6 +49,8 @@
 
     private AbstractJcrProperty prop;
     @Mock
+    private Session session;
+    @Mock
     private Node node;
     @Mock
     private ExecutionContext executionContext;
@@ -55,8 +58,9 @@
     private Name name;
 
     @Before
-    public void before() {
+    public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
+        stub(node.getSession()).toReturn(session);
         prop = new MockAbstractJcrProperty(node, executionContext, name);
     }
 
@@ -67,6 +71,11 @@
         Mockito.verify(visitor).visit(prop);
     }
 
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowVisitationIfNoVisitor() throws Exception {
+        prop.accept(null);
+    }
+
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNoSession() throws Exception {
         new MockAbstractJcrProperty(null, executionContext, name);
@@ -102,10 +111,8 @@
     }
 
     @Test
-    public void shouldProvideSession() throws Exception {
-        Session session = Mockito.mock(Session.class);
-        stub(node.getSession()).toReturn(session);
-        assertThat(prop.getSession(), is(session));
+    public void shouldProvideDepth() throws Exception {
+        assertThat(prop.getDepth(), is(1));
     }
 
     @Test
@@ -137,7 +144,14 @@
     }
 
     @Test
-    public void shouldNotBeANode() {
+    public void shouldProvideSession() throws Exception {
+        Session session = Mockito.mock(Session.class);
+        stub(node.getSession()).toReturn(session);
+        assertThat(prop.getSession(), is(session));
+    }
+
+    @Test
+    public void shouldIndicateIsNotANode() {
         assertThat(prop.isNode(), is(false));
     }
 
@@ -145,6 +159,7 @@
     public void shouldIndicateSameAsNodeWithSameParentAndName() throws Exception {
         stub(name.getString()).toReturn("propertyName");
         Node otherNode = Mockito.mock(Node.class);
+        stub(otherNode.getSession()).toReturn(session);
         Name otherName = Mockito.mock(Name.class);
         stub(otherName.getString()).toReturn("propertyName");
         stub(node.isSame(otherNode)).toReturn(true);
@@ -156,6 +171,7 @@
     public void shouldIndicateDifferentThanNodeWithDifferentParent() throws Exception {
         stub(name.getString()).toReturn("propertyName");
         Node otherNode = Mockito.mock(Node.class);
+        stub(otherNode.getSession()).toReturn(session);
         Name otherName = Mockito.mock(Name.class);
         stub(otherName.getString()).toReturn("propertyName");
         stub(node.isSame(otherNode)).toReturn(false);
@@ -167,6 +183,7 @@
     public void shouldIndicateDifferentThanNodeWithDifferentName() throws Exception {
         stub(name.getString()).toReturn("propertyName");
         Node otherNode = Mockito.mock(Node.class);
+        stub(otherNode.getSession()).toReturn(session);
         Name otherName = Mockito.mock(Name.class);
         stub(otherName.getString()).toReturn("propertyName2");
         stub(node.isSame(otherNode)).toReturn(true);
@@ -174,6 +191,56 @@
         assertThat(prop.isSame(otherProp), is(false));
     }
 
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetBooleanValue() {
+        prop.setValue(false);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetCalendarValue() {
+        prop.setValue(Calendar.getInstance());
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetDoubleValue() {
+        prop.setValue(0.0);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetInputStreamValue() {
+        prop.setValue(Mockito.mock(InputStream.class));
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetLongValue() {
+        prop.setValue(0L);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetNodeValue() {
+        prop.setValue(Mockito.mock(Node.class));
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetStringValue() {
+        prop.setValue("");
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetStringArrayValue() {
+        prop.setValue(StringUtil.EMPTY_STRING_ARRAY);
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetValueValue() {
+        prop.setValue(Mockito.mock(Value.class));
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowSetValueArrayValue() {
+        prop.setValue(new Value[0]);
+    }
+
     private class MockAbstractJcrProperty extends AbstractJcrProperty {
 
         MockAbstractJcrProperty( Node node,
@@ -203,15 +270,6 @@
         /**
          * {@inheritDoc}
          * 
-         * @see javax.jcr.Item#getDepth()
-         */
-        public int getDepth() {
-            return 0;
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
          * @see javax.jcr.Property#getDouble()
          */
         public double getDouble() {

Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java	                        (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -0,0 +1,179 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.jcr;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.Arrays;
+import java.util.Calendar;
+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 org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.connector.BasicExecutionContext;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+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 JcrMultiValuePropertyTest {
+
+    @Mock
+    private Node node;
+    private ExecutionContext executionContext = new BasicExecutionContext();
+    @Mock
+    Name name;
+
+    @Before
+    public void before() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNoValue() {
+        new JcrMultiValueProperty(node, executionContext, name, null);
+    }
+
+    @Test
+    public void shouldProvideAppropriateType() throws Exception {
+        Property prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(true));
+        assertThat(prop.getType(), is(PropertyType.BOOLEAN));
+        Calendar cal = Calendar.getInstance();
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(cal));
+        assertThat(prop.getType(), is(PropertyType.DATE));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(cal.getTime()));
+        assertThat(prop.getType(), is(PropertyType.DATE));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1.0));
+        assertThat(prop.getType(), is(PropertyType.DOUBLE));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1.0F));
+        assertThat(prop.getType(), is(PropertyType.DOUBLE));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1));
+        assertThat(prop.getType(), is(PropertyType.LONG));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1L));
+        assertThat(prop.getType(), is(PropertyType.LONG));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(new Object()));
+        assertThat(prop.getType(), is(PropertyType.BINARY));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList("value"));
+        assertThat(prop.getType(), is(PropertyType.STRING));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(UUID.randomUUID()));
+        assertThat(prop.getType(), is(PropertyType.REFERENCE));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(Mockito.mock(Reader.class)));
+        assertThat(prop.getType(), is(PropertyType.BINARY));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(Mockito.mock(InputStream.class)));
+        assertThat(prop.getType(), is(PropertyType.BINARY));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(new Object()));
+        assertThat(prop.getType(), is(PropertyType.BINARY));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(name));
+        assertThat(prop.getType(), is(PropertyType.NAME));
+        prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(Mockito.mock(Path.class)));
+        assertThat(prop.getType(), is(PropertyType.PATH));
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideBoolean() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(true)).getBoolean();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideDateForCalendar() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(Calendar.getInstance())).getDate();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideDateForDate() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(Calendar.getInstance().getTime())).getDate();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideDoubleForDouble() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1.0)).getDouble();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideDoubleForFloat() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1.0F)).getDouble();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideLongForInteger() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1)).getLong();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideLongForLong() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(1L)).getLong();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideStream() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(new Object())).getStream();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideString() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList("value")).getString();
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideValue() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(true)).getValue();
+    }
+
+    @Test
+    public void shouldProvideValues() throws Exception {
+        Property prop = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(true));
+        Value[] vals = prop.getValues();
+        assertThat(vals, notNullValue());
+        assertThat(vals.length, is(1));
+        assertThat(vals[0].getBoolean(), is(true));
+    }
+
+    @Test( expected = ValueFormatException.class )
+    public void shouldNotProvideLength() throws Exception {
+        new JcrMultiValueProperty(node, executionContext, name, Arrays.asList("value")).getLength();
+    }
+
+    @Test
+    public void shouldProvideLengths() throws Exception {
+        long[] lengths = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList("value")).getLengths();
+        assertThat(lengths, notNullValue());
+        assertThat(lengths.length, is(1));
+        assertThat(lengths[0], is(5L));
+        Object obj = new Object();
+        lengths = new JcrMultiValueProperty(node, executionContext, name, Arrays.asList(obj)).getLengths();
+        assertThat(lengths, notNullValue());
+        assertThat(lengths.length, is(1));
+        assertThat(lengths[0], is((long)obj.toString().length()));
+    }
+}


Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -53,10 +53,13 @@
     public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
         root = new JcrRootNode(session);
+        Segment segment = Mockito.mock(Segment.class);
         Name name = Mockito.mock(Name.class);
         stub(name.getString()).toReturn("name");
+        stub(segment.getName()).toReturn(name);
+        stub(segment.getIndex()).toReturn(2);
         UUID uuid = UUID.randomUUID();
-        node = new JcrNode(session, uuid, name);
+        node = new JcrNode(session, uuid, segment);
         stub(session.getNodeByUUID(uuid.toString())).toReturn(root);
         node.setProperties(new HashSet<Property>());
         node.setChildren(new ArrayList<Segment>());
@@ -68,17 +71,22 @@
     }
 
     @Test
-    public void shouldHaveZeroDepth() throws Exception {
+    public void shouldProvideDepth() throws Exception {
         assertThat(node.getDepth(), is(1));
     }
 
     @Test
+    public void shouldProvideIndex() throws Exception {
+        assertThat(node.getIndex(), is(2));
+    }
+
+    @Test
     public void shouldProvideName() throws Exception {
         assertThat(node.getName(), is("name"));
     }
 
     @Test
     public void shouldProvidePath() throws Exception {
-        assertThat(node.getPath(), is("/name"));
+        assertThat(node.getPath(), is("/name[2]"));
     }
 }

Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -1,180 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors. 
- *
- * This is free software; you can redistribute it and/or modify it
- * 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.
- *
- * This software 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.IsNot.not;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.junit.Assert.assertThat;
-import java.util.HashSet;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-/**
- * @author jverhaeg
- */
-public class JcrPropertyIteratorTest {
-
-    @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoProperties() throws Exception {
-        new JcrPropertyIterator(null);
-    }
-
-    @Test
-    public void shouldIndicateWhenPropertiesRemain() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        assertThat(iter.hasNext(), is(false));
-        props.add(Mockito.mock(Property.class));
-        iter = new JcrPropertyIterator(props);
-        assertThat(iter.hasNext(), is(true));
-    }
-
-    @Test
-    public void shouldAllowNextWhenPropertiesRemain() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        Property prop1 = Mockito.mock(Property.class);
-        props.add(prop1);
-        Property prop2 = Mockito.mock(Property.class);
-        props.add(prop2);
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        Property iterProp1 = (Property)iter.next();
-        assertThat(iterProp1, notNullValue());
-        Property iterProp2 = (Property)iter.next();
-        assertThat(iterProp2, notNullValue());
-        assertThat(iterProp1, is(not(iterProp2)));
-    }
-
-    @Test( expected = NoSuchElementException.class )
-    public void shouldNotAllowNextWhenNoPropertiesRemain() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.next();
-    }
-
-    @Test
-    public void shouldAllowNextPropertyWhenPropertiesRemain() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        Property prop1 = Mockito.mock(Property.class);
-        props.add(prop1);
-        Property prop2 = Mockito.mock(Property.class);
-        props.add(prop2);
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        Property iterProp1 = iter.nextProperty();
-        assertThat(iterProp1, notNullValue());
-        Property iterProp2 = iter.nextProperty();
-        assertThat(iterProp2, notNullValue());
-        assertThat(iterProp1, is(not(iterProp2)));
-    }
-
-    @Test( expected = NoSuchElementException.class )
-    public void shouldNotAllowNextPropertyWhenNoPropertiesRemain() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.nextProperty();
-    }
-
-    @Test
-    public void shouldAllowRemoveAfterNext() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        props.add(Mockito.mock(Property.class));
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.next();
-        iter.remove();
-        assertThat(props.isEmpty(), is(true));
-    }
-
-    @Test( expected = IllegalStateException.class )
-    public void shouldNotAllowRemoveBeforeNext() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        props.add(Mockito.mock(Property.class));
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.remove();
-    }
-
-    @Test( expected = IllegalStateException.class )
-    public void shouldNotAllowRemoveTwice() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        props.add(Mockito.mock(Property.class));
-        props.add(Mockito.mock(Property.class));
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.next();
-        iter.remove();
-        iter.remove();
-    }
-
-    @Test
-    public void shouldProvideSize() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        assertThat(iter.getSize(), is(0L));
-        props.add(Mockito.mock(Property.class));
-        iter = new JcrPropertyIterator(props);
-        assertThat(iter.getSize(), is(1L));
-        iter.next();
-        iter.remove();
-        assertThat(iter.getSize(), is(0L));
-    }
-
-    @Test
-    public void shouldProvidePosition() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        assertThat(iter.getPosition(), is(0L));
-        props.add(Mockito.mock(Property.class));
-        iter = new JcrPropertyIterator(props);
-        assertThat(iter.getPosition(), is(0L));
-        iter.next();
-        assertThat(iter.getPosition(), is(1L));
-        iter.remove();
-        assertThat(iter.getPosition(), is(1L));
-    }
-
-    @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNegativeSkip() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.skip(-1);
-    }
-
-    @Test
-    public void shouldAllowSkip() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        props.add(Mockito.mock(Property.class));
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.skip(0);
-        assertThat(iter.hasNext(), is(true));
-        iter.skip(1);
-        assertThat(iter.hasNext(), is(false));
-    }
-
-    @Test( expected = NoSuchElementException.class )
-    public void shouldNotAllowSkipPastRemainingProperties() throws Exception {
-        Set<Property> props = new HashSet<Property>();
-        PropertyIterator iter = new JcrPropertyIterator(props);
-        iter.skip(1);
-    }
-}

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyTest.java	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -24,7 +24,6 @@
 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.io.InputStream;
 import java.io.Reader;
 import java.util.Calendar;
@@ -105,10 +104,16 @@
 
     @Test
     public void shouldProvideStream() throws Exception {
-        Property prop = new JcrProperty(node, executionContext, name, "value");
+        Property prop = new JcrProperty(node, executionContext, name, new Object());
         InputStream stream = prop.getStream();
-        assertThat(stream, notNullValue());
-        stream.close();
+        try {
+            assertThat(stream, notNullValue());
+            assertThat(prop.getType(), is(PropertyType.BINARY));
+        } finally {
+            if (stream != null) {
+                stream.close();
+            }
+        }
     }
 
     @Test
@@ -172,11 +177,4 @@
     public void shouldNotProvideLengths() throws Exception {
         new JcrProperty(node, executionContext, name, "value").getLengths();
     }
-
-    @Test
-    public void shouldProvideDepth() throws Exception {
-        Property prop = new JcrProperty(node, executionContext, name, true);
-        stub(node.getDepth()).toReturn(0);
-        assertThat(prop.getDepth(), is(1));
-    }
 }

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -99,6 +99,16 @@
         new JcrRepository(executionContextFactory, null);
     }
 
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowNoDescriptorKey() {
+        repository.getDescriptor(null);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowEmptyDescriptorKey() {
+        repository.getDescriptor("");
+    }
+
     @Test
     public void shouldProvideBuiltInDescriptorKeys() {
         testDescriptorKeys(repository);

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -45,7 +45,7 @@
     private Set<Property> properties;
 
     @Before
-    public void before() {
+    public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
         properties = new HashSet<Property>();
         root = new JcrRootNode(session);
@@ -58,12 +58,17 @@
     }
 
     @Test
-    public void shouldHaveZeroDepth() {
+    public void shouldHaveZeroDepth() throws Exception {
         assertThat(root.getDepth(), is(0));
     }
 
     @Test
-    public void shouldHaveEmptyName() {
+    public void shouldIndicateIndexIsOne() throws Exception {
+        assertThat(root.getIndex(), is(1));
+    }
+
+    @Test
+    public void shouldHaveEmptyName() throws Exception {
         String name = root.getName();
         assertThat(name, notNullValue());
         assertThat(name.length(), is(0));
@@ -75,7 +80,7 @@
     }
 
     @Test
-    public void shouldProvidePath() {
+    public void shouldProvidePath() throws Exception {
         assertThat(root.getPath(), is("/"));
     }
 }

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	2008-09-08 16:28:03 UTC (rev 508)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java	2008-09-09 15:18:27 UTC (rev 509)
@@ -27,8 +27,11 @@
 import static org.hamcrest.core.IsNull.nullValue;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.stub;
+import java.io.InputStream;
 import java.lang.ref.WeakReference;
+import java.security.AccessControlException;
 import java.security.Principal;
+import java.util.Calendar;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -36,8 +39,10 @@
 import javax.jcr.Item;
 import javax.jcr.Node;
 import javax.jcr.Property;
+import javax.jcr.PropertyType;
 import javax.jcr.Repository;
 import javax.jcr.Session;
+import javax.jcr.ValueFactory;
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 import org.jboss.dna.spi.ExecutionContext;
@@ -125,7 +130,42 @@
         new JcrSession(repository, executionContext, WORKSPACE_NAME, connection, null);
     }
 
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowAddLockToken() throws Exception {
+        session.addLockToken(null);
+    }
+
     @Test
+    public void shouldAllowCheckReadPermission() throws Exception {
+        session.checkPermission("/", "read");
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowCheckPermissionWithNoPath() throws Exception {
+        session.checkPermission(null, "read");
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowCheckPermissionWithEmptyPath() throws Exception {
+        session.checkPermission("", "read");
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowCheckPermissionWithNoActions() throws Exception {
+        session.checkPermission("/", null);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowCheckPermissionWithEmptyActions() throws Exception {
+        session.checkPermission("/", "");
+    }
+
+    @Test( expected = AccessControlException.class )
+    public void shouldNotAllowCheckNonReadPermission() throws Exception {
+        session.checkPermission("/", "any");
+    }
+
+    @Test
     public void shouldProvideNoAttributes() throws Exception {
         assertThat(session.getAttribute(null), nullValue());
     }
@@ -148,7 +188,7 @@
     }
 
     @Test
-    public void shouldBeLiveBeforeLogout() throws Exception {
+    public void shouldIndicateLiveBeforeLogout() throws Exception {
         assertThat(session.isLive(), is(true));
     }
 
@@ -158,7 +198,7 @@
     }
 
     @Test
-    public void shouldNotBeLiveAfterLogout() throws Exception {
+    public void shouldIndicateNotLiveAfterLogout() throws Exception {
         session.logout();
         assertThat(session.isLive(), is(false));
     }
@@ -205,4 +245,35 @@
         item = session.getItem("/a/b/booleanProperty");
         assertThat(item, instanceOf(Property.class));
     }
+
+    @Test
+    public void shouldProvideValueFactory() throws Exception {
+        ValueFactory factory = session.getValueFactory();
+        assertThat(factory, notNullValue());
+        assertThat(factory.createValue(false), notNullValue());
+        assertThat(factory.createValue(Calendar.getInstance()), notNullValue());
+        assertThat(factory.createValue(0.0), notNullValue());
+        assertThat(factory.createValue(Mockito.mock(InputStream.class)), notNullValue());
+        assertThat(factory.createValue(0L), notNullValue());
+        Node node = Mockito.mock(Node.class);
+        stub(node.getUUID()).toReturn(UUID.randomUUID().toString());
+        assertThat(factory.createValue(node), notNullValue());
+        assertThat(factory.createValue(""), notNullValue());
+        assertThat(factory.createValue("", PropertyType.BINARY), notNullValue());
+    }
+
+    @Test
+    public void shouldNotHavePendingChanges() throws Exception {
+        assertThat(session.hasPendingChanges(), is(false));
+    }
+
+    @Test
+    public void shouldAllowImpersonation() throws Exception {
+        assertThat(session.impersonate(null), notNullValue());
+    }
+
+    @Test
+    public void shouldProvideItemExists() throws Exception {
+        assertThat(session.itemExists(""), is(false));
+    }
 }




More information about the dna-commits mailing list