jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r792142 [3/35] - in /jackrabbit/sandbox/JCR-1456: ./ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/ jackrabbit-core/ jackrabbit-core/src/main/java/org/apache/jackrabb...
Date Wed, 08 Jul 2009 13:57:46 GMT
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java?rev=792142&r1=792141&r2=792142&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java Wed Jul  8 13:57:13 2009
@@ -93,7 +93,7 @@
     /**
      * A cache for item instances created by this <code>ItemManager</code>
      */
-    private final Map itemCache;
+    private final Map<ItemId, ItemData> itemCache;
 
     /**
      * Shareable node cache.
@@ -200,7 +200,7 @@
             if (!itemStateProvider.hasItemState(itemId)) {
                 return false;
             }
-            ItemData data = getItemData(itemId, path, true);
+            getItemData(itemId, path, true);
             return true;
         } catch (RepositoryException re) {
             return false;
@@ -430,14 +430,19 @@
      * @throws AccessDeniedException
      * @throws RepositoryException
      */
-    public ItemImpl getItem(Path path)
-            throws PathNotFoundException, AccessDeniedException, RepositoryException {
+    public ItemImpl getItem(Path path) throws PathNotFoundException,
+            AccessDeniedException, RepositoryException {
         ItemId id = hierMgr.resolvePath(path);
         if (id == null) {
             throw new PathNotFoundException(safeGetJCRPath(path));
         }
         try {
-            return getItem(id, path);
+            ItemImpl item = getItem(id, path);
+            // Test, if this item is a shareable node.
+            if (item.isNode() && ((NodeImpl) item).isShareable()) {
+                return getNode(path);
+            }
+            return item;
         } catch (ItemNotFoundException infe) {
             throw new PathNotFoundException(safeGetJCRPath(path));
         }
@@ -450,14 +455,23 @@
      * @throws AccessDeniedException
      * @throws RepositoryException
      */
-    public NodeImpl getNode(Path path)
-            throws PathNotFoundException, AccessDeniedException, RepositoryException {
+    public NodeImpl getNode(Path path) throws PathNotFoundException,
+            AccessDeniedException, RepositoryException {
         NodeId id = hierMgr.resolveNodePath(path);
         if (id == null) {
             throw new PathNotFoundException(safeGetJCRPath(path));
         }
+        NodeId parentId = null;
+        if (!path.denotesRoot()) {
+            parentId = hierMgr.resolveNodePath(path.getAncestor(1));
+        }
         try {
-            return (NodeImpl) getItem(id, path);
+            if (parentId == null) {
+                return (NodeImpl) getItem(id, path);
+            }
+            // if the node is shareable, it now returns the node with the right
+            // parent
+            return getNode(id, parentId);
         } catch (ItemNotFoundException infe) {
             throw new PathNotFoundException(safeGetJCRPath(path));
         }
@@ -589,11 +603,11 @@
             log.debug(msg);
             throw new RepositoryException(msg);
         }
-        ArrayList childIds = new ArrayList();
-        Iterator iter = ((NodeState) data.getState()).getChildNodeEntries().iterator();
+        ArrayList<ItemId> childIds = new ArrayList<ItemId>();
+        Iterator<ChildNodeEntry> iter = ((NodeState) data.getState()).getChildNodeEntries().iterator();
 
         while (iter.hasNext()) {
-            ChildNodeEntry entry = (ChildNodeEntry) iter.next();
+            ChildNodeEntry entry = iter.next();
             // delay check for read-access until item is being built
             // thus avoid duplicate check
             childIds.add(entry.getId());
@@ -620,10 +634,10 @@
             log.debug(msg);
             throw new RepositoryException(msg);
         }
-        Iterator iter = ((NodeState) data.getState()).getPropertyNames().iterator();
+        Iterator<Name> iter = ((NodeState) data.getState()).getPropertyNames().iterator();
 
         while (iter.hasNext()) {
-            Name propName = (Name) iter.next();
+            Name propName = iter.next();
             // make sure any of the properties can be read.
             if (canRead(new PropertyId(parentId, propName))) {
                 return true;
@@ -651,11 +665,11 @@
             log.debug(msg);
             throw new RepositoryException(msg);
         }
-        ArrayList childIds = new ArrayList();
-        Iterator iter = ((NodeState) data.getState()).getPropertyNames().iterator();
+        ArrayList<PropertyId> childIds = new ArrayList<PropertyId>();
+        Iterator<Name> iter = ((NodeState) data.getState()).getPropertyNames().iterator();
 
         while (iter.hasNext()) {
-            Name propName = (Name) iter.next();
+            Name propName = iter.next();
             PropertyId id = new PropertyId(parentId, propName);
             // delay check for read-access until item is being built
             // thus avoid duplicate check
@@ -738,7 +752,7 @@
      */
     private ItemData retrieveItem(ItemId id) {
         synchronized (itemCache) {
-            ItemData data = (ItemData) itemCache.get(id);
+            ItemData data = itemCache.get(id);
             if (data == null && id.denotesNode()) {
                 data = shareableNodesCache.retrieveFirst((NodeId) id);
             }
@@ -821,7 +835,7 @@
             if (data.isNode()) {
                 shareableNodesCache.evict((AbstractNodeData) data);
             }
-            ItemData cached = (ItemData) itemCache.get(data.getId());
+            ItemData cached = itemCache.get(data.getId());
             if (cached == data) {
                 itemCache.remove(data.getId());
             }
@@ -899,10 +913,8 @@
         ps.println("Items in cache:");
         ps.println();
         synchronized (itemCache) {
-            Iterator iter = itemCache.keySet().iterator();
-            while (iter.hasNext()) {
-                ItemId id = (ItemId) iter.next();
-                ItemData item = (ItemData) itemCache.get(id);
+            for (ItemId id : itemCache.keySet()) {
+                ItemData item = itemCache.get(id);
                 if (item.isNode()) {
                     ps.print("Node: ");
                 } else {
@@ -1070,10 +1082,10 @@
         public AbstractNodeData retrieveFirst(NodeId id) {
             ReferenceMap map = (ReferenceMap) cache.get(id);
             if (map != null) {
-                Iterator iter = map.values().iterator();
+                Iterator<AbstractNodeData> iter = map.values().iterator();
                 try {
                     while (iter.hasNext()) {
-                        AbstractNodeData data = (AbstractNodeData) iter.next();
+                        AbstractNodeData data = iter.next();
                         if (data != null) {
                             return data;
                         }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java?rev=792142&r1=792141&r2=792142&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java Wed Jul  8 13:57:13 2009
@@ -28,6 +28,8 @@
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Properties;
+import java.util.Map;
+import java.util.HashMap;
 
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
@@ -80,9 +82,24 @@
     private final Properties settings;
 
     /**
-     * The repository instance.
+     * Map of repository instances. Key = repository home, value = repository
+     * instance.
      */
-    private Repository repository;
+    private static final Map<String, Repository> REPOSITORY_INSTANCES = new HashMap<String, Repository>();
+
+    static {
+        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+            public void run() {
+                synchronized (REPOSITORY_INSTANCES) {
+                    for (Repository repo : REPOSITORY_INSTANCES.values()) {
+                        if (repo instanceof RepositoryImpl) {
+                            ((RepositoryImpl) repo).shutdown();
+                        }
+                    }
+                }
+            }
+        }));
+    }
 
     private static Properties getStaticProperties() {
         Properties properties = new Properties();
@@ -129,33 +146,27 @@
      */
     public synchronized Repository getRepository()
             throws RepositoryStubException {
-        if (repository == null) {
-            try {
-                String dir = settings.getProperty(PROP_REPOSITORY_HOME);
-                if (dir == null) {
-                    dir = new File("target", "repository").getPath();
-                }
+        try {
+            String dir = settings.getProperty(PROP_REPOSITORY_HOME);
+            if (dir == null) {
+                dir = new File("target", "repository").getAbsolutePath();
+            } else {
+                dir = new File(dir).getAbsolutePath();
+            }
 
-                String xml = settings.getProperty(PROP_REPOSITORY_CONFIG);
-                if (xml == null) {
-                    xml = new File(dir, "repository.xml").getPath();
-                }
+            String xml = settings.getProperty(PROP_REPOSITORY_CONFIG);
+            if (xml == null) {
+                xml = new File(dir, "repository.xml").getPath();
+            }
 
-                repository = createRepository(dir, xml);
-                Session session = repository.login(superuser);
-                try {
-                    prepareTestContent(session);
-                } finally {
-                    session.logout();
-                }
-            } catch (Exception e) {
-                RepositoryStubException exception =
+            return getOrCreateRepository(dir, xml);
+
+        } catch (Exception e) {
+            RepositoryStubException exception =
                     new RepositoryStubException("Failed to start repository");
-                exception.initCause(e);
-                throw exception;
-            }
+            exception.initCause(e);
+            throw exception;
         }
-        return repository;
     }
 
     protected Repository createRepository(String dir, String xml)
@@ -180,6 +191,25 @@
         return RepositoryImpl.create(config);
     }
 
+    protected Repository getOrCreateRepository(String dir, String xml)
+            throws Exception {
+        synchronized (REPOSITORY_INSTANCES) {
+            Repository repo = REPOSITORY_INSTANCES.get(dir);
+            if (repo == null) {
+                repo = createRepository(dir, xml);
+                Session session = repo.login(superuser);
+                try {
+                    prepareTestContent(session);
+                } finally {
+                    session.logout();
+                }
+
+                REPOSITORY_INSTANCES.put(dir, repo);
+            }
+            return repo;
+        }
+    }
+
     private void prepareTestContent(Session session)
             throws RepositoryException, IOException {
         JackrabbitWorkspace workspace =
@@ -278,6 +308,8 @@
         }
 
         Node resource = node.addNode("myResource", "nt:resource");
+        // nt:resource not longer referenceable since JCR 2.0
+        resource.addMixin("mix:referenceable");
         resource.setProperty("jcr:encoding", ENCODING);
         resource.setProperty("jcr:mimeType", "text/plain");
         resource.setProperty(

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java?rev=792142&r1=792141&r2=792142&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java Wed Jul  8 13:57:13 2009
@@ -45,7 +45,7 @@
  *
  * @see #getSize()
  */
-class LazyItemIterator implements NodeIterator, PropertyIterator {
+public class LazyItemIterator implements NodeIterator, PropertyIterator {
 
     /** Logger instance for this class */
     private static Logger log = LoggerFactory.getLogger(LazyItemIterator.class);
@@ -54,7 +54,7 @@
     private final ItemManager itemMgr;
 
     /** the list of item ids */
-    private final List idList;
+    private final List<ItemId> idList;
 
     /** parent node id (when returning children nodes) or <code>null</code> */
     private final NodeId parentId;
@@ -71,7 +71,7 @@
      * @param itemMgr item manager
      * @param idList  list of item id's
      */
-    public LazyItemIterator(ItemManager itemMgr, List idList) {
+    public LazyItemIterator(ItemManager itemMgr, List< ? extends ItemId> idList) {
         this(itemMgr, idList, null);
     }
 
@@ -84,9 +84,9 @@
      * @param idList  list of item id's
      * @param parentId parent id.
      */
-    public LazyItemIterator(ItemManager itemMgr, List idList, NodeId parentId) {
+    public LazyItemIterator(ItemManager itemMgr, List< ? extends ItemId> idList, NodeId parentId) {
         this.itemMgr = itemMgr;
-        this.idList = new ArrayList(idList);
+        this.idList = new ArrayList<ItemId>(idList);
         this.parentId = parentId;
         // prefetch first item
         pos = 0;
@@ -103,7 +103,7 @@
         // reset
         next = null;
         while (next == null && pos < idList.size()) {
-            ItemId id = (ItemId) idList.get(pos);
+            ItemId id = idList.get(pos);
             try {
                 if (parentId != null) {
                     next = itemMgr.getNode((NodeId) id, parentId);
@@ -190,7 +190,7 @@
                 // skipped past last item
                 throw new NoSuchElementException();
             }
-            ItemId id = (ItemId) idList.get(pos);
+            ItemId id = idList.get(pos);
             // eliminate invalid items from this iterator
             while (!itemMgr.itemExists(id)) {
                 log.debug("ignoring nonexistent item " + id);
@@ -200,9 +200,7 @@
                     // skipped past last item
                     throw new NoSuchElementException();
                 }
-                id = (ItemId) idList.get(pos);
-                // try next
-                continue;
+                id = idList.get(pos);
             }
         }
         // prefetch final item (the one to be returned on next())

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java?rev=792142&r1=792141&r2=792142&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java Wed Jul  8 13:57:13 2009
@@ -30,7 +30,6 @@
 import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Properties;
 
 import javax.jcr.AccessDeniedException;
@@ -50,8 +49,8 @@
     private static final String NS_REG_RESOURCE = "ns_reg.properties";
     private static final String NS_IDX_RESOURCE = "ns_idx.properties";
 
-    private static final HashSet reservedPrefixes = new HashSet();
-    private static final HashSet reservedURIs = new HashSet();
+    private static final HashSet<String> reservedPrefixes = new HashSet<String>();
+    private static final HashSet<String> reservedURIs = new HashSet<String>();
 
     static {
         // reserved prefixes
@@ -74,13 +73,13 @@
         reservedURIs.add(Name.NS_SV_URI);
     }
 
-    private HashMap prefixToURI = new HashMap();
-    private HashMap uriToPrefix = new HashMap();
+    private HashMap<String, String> prefixToURI = new HashMap<String, String>();
+    private HashMap<String, String> uriToPrefix = new HashMap<String, String>();
 
-    private HashMap indexToURI = new HashMap();
-    private HashMap uriToIndex = new HashMap();
+    private HashMap<Integer, String> indexToURI = new HashMap<Integer, String>();
+    private HashMap<String, Integer> uriToIndex = new HashMap<String, Integer>();
 
-    private int lastIndex = 0;
+    private int lastIndex;
 
     private final FileSystem nsRegStore;
 
@@ -133,7 +132,7 @@
         uriToPrefix.put(uri, prefix);
         if (!uriToIndex.containsKey(uri)) {
             if (idx == null) {
-                idx = new Integer(++lastIndex);
+                idx = ++lastIndex;
             } else {
                 if (idx.intValue() > lastIndex) {
                     lastIndex = idx.intValue();
@@ -196,9 +195,8 @@
                 clear();
 
                 // read mappings from properties
-                Iterator iter = props.keySet().iterator();
-                while (iter.hasNext()) {
-                    String prefix = (String) iter.next();
+                for (Object p : props.keySet()) {
+                    String prefix = (String) p;
                     String uri = props.getProperty(prefix);
                     String idx = indexes.getProperty(uri);
                     if (idx != null) {
@@ -229,10 +227,8 @@
             Properties props = new Properties();
 
             // store mappings in properties
-            Iterator iter = prefixToURI.keySet().iterator();
-            while (iter.hasNext()) {
-                String prefix = (String) iter.next();
-                String uri = (String) prefixToURI.get(prefix);
+            for (String prefix : prefixToURI.keySet()) {
+                String uri = prefixToURI.get(prefix);
                 props.setProperty(prefix, uri);
             }
 
@@ -256,9 +252,7 @@
             Properties props = new Properties();
 
             // store mappings in properties
-            Iterator iter = uriToIndex.keySet().iterator();
-            while (iter.hasNext()) {
-                String uri = (String) iter.next();
+            for (String uri : uriToIndex.keySet()) {
                 String index = uriToIndex.get(uri).toString();
                 props.setProperty(uri, index);
             }
@@ -296,7 +290,7 @@
      * @throws IllegalArgumentException if the namespace is not registered
      */
     public int stringToIndex(String uri) {
-        Integer idx = (Integer) uriToIndex.get(uri);
+        Integer idx = uriToIndex.get(uri);
         if (idx == null) {
             throw new IllegalArgumentException("Namespace not registered: " + uri);
         }
@@ -311,7 +305,7 @@
      * @throws IllegalArgumentException if the given index is invalid
      */
     public String indexToString(int idx) {
-        String uri = (String) indexToURI.get(new Integer(idx));
+        String uri = indexToURI.get(idx);
         if (uri == null) {
             throw new IllegalArgumentException("Invalid namespace index: " + idx);
         }
@@ -351,7 +345,7 @@
         }
 
         // check existing mappings
-        String oldPrefix = (String) uriToPrefix.get(uri);
+        String oldPrefix = uriToPrefix.get(uri);
         if (prefix.equals(oldPrefix)) {
             throw new NamespaceException("failed to register namespace "
                     + prefix + " -> " + uri + ": mapping already exists");
@@ -409,14 +403,14 @@
      * {@inheritDoc}
      */
     public String[] getPrefixes() throws RepositoryException {
-        return (String[]) prefixToURI.keySet().toArray(new String[prefixToURI.keySet().size()]);
+        return prefixToURI.keySet().toArray(new String[prefixToURI.keySet().size()]);
     }
 
     /**
      * {@inheritDoc}
      */
     public String[] getURIs() throws RepositoryException {
-        return (String[]) uriToPrefix.keySet().toArray(new String[uriToPrefix.keySet().size()]);
+        return uriToPrefix.keySet().toArray(new String[uriToPrefix.keySet().size()]);
     }
 
     //---------------------------------------------------< NamespaceRegistry >
@@ -424,7 +418,7 @@
      * {@inheritDoc}
      */
     public String getURI(String prefix) throws NamespaceException {
-        String uri = (String) prefixToURI.get(prefix);
+        String uri = prefixToURI.get(prefix);
         if (uri == null) {
             throw new NamespaceException(prefix
                     + ": is not a registered namespace prefix.");
@@ -436,7 +430,7 @@
      * {@inheritDoc}
      */
     public String getPrefix(String uri) throws NamespaceException {
-        String prefix = (String) uriToPrefix.get(uri);
+        String prefix = uriToPrefix.get(uri);
         if (prefix == null) {
             throw new NamespaceException(uri
                     + ": is not a registered namespace uri.");

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=792142&r1=792141&r2=792142&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Wed Jul  8 13:57:13 2009
@@ -26,6 +26,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Binary;
@@ -95,6 +97,7 @@
 import org.apache.jackrabbit.core.version.LabelVersionSelector;
 import org.apache.jackrabbit.core.version.VersionImpl;
 import org.apache.jackrabbit.core.version.VersionSelector;
+import org.apache.jackrabbit.core.query.QueryManagerImpl;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
@@ -103,6 +106,7 @@
 import org.apache.jackrabbit.spi.commons.name.PathBuilder;
 import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
 import org.apache.jackrabbit.util.ChildrenCollectorFilter;
+import org.apache.jackrabbit.util.ISO9075;
 import org.apache.jackrabbit.uuid.UUID;
 import org.apache.jackrabbit.value.ValueHelper;
 import org.slf4j.Logger;
@@ -202,36 +206,23 @@
      */
     protected NodeId resolveRelativeNodePath(String relPath)
             throws RepositoryException {
+
+        Path p = resolveRelativePath(relPath);
+        return getNodeId(p);
+    }
+
+    /**
+     * Resolve a relative path given as string into a <code>Path</code>. If
+     * a <code>NameException</code> occurs, it will be rethrown embedded
+     * into a <code>RepositoryException</code>
+     *
+     * @param relPath relative path
+     * @return <code>Path</code> object
+     * @throws RepositoryException if an error occurs
+     */
+    private Path resolveRelativePath(String relPath) throws RepositoryException {
         try {
-            /**
-             * first check if relPath is just a name (in which case we don't
-             * have to build & resolve absolute path)
-             */
-            Path p = session.getQPath(relPath);
-            if (p.getLength() == 1) {
-                Path.Element pe = p.getNameElement();
-                if (pe.denotesName()) {
-                    // check if node entry exists
-                    NodeState thisState = data.getNodeState();
-                    int index = pe.getIndex();
-                    if (index == 0) {
-                        index = 1;
-                    }
-                    ChildNodeEntry cne =
-                            thisState.getChildNodeEntry(pe.getName(), index);
-                    if (cne != null) {
-                        return cne.getId();
-                    } else {
-                        // there's no child node with that name
-                        return null;
-                    }
-                }
-            }
-            /**
-             * build and resolve absolute path
-             */
-            p = PathFactoryImpl.getInstance().create(getPrimaryPath(), p, true);
-            return session.getHierarchyManager().resolveNodePath(p);
+            return session.getQPath(relPath);
         } catch (NameException e) {
             String msg = "failed to resolve path " + relPath + " relative to " + this;
             log.debug(msg);
@@ -240,6 +231,45 @@
     }
 
     /**
+     * Returns the id of the node at <code>p</code> or <code>null</code>
+     * if no node exists at <code>p</code>.
+     * <p/>
+     * Note that access rights are not checked.
+     *
+     * @param p relative path of a (possible) node
+     * @return the id of the node at <code>p</code> or
+     *         <code>null</code> if no node exists at <code>p</code>
+     * @throws RepositoryException if <code>relPath</code> is not a valid
+     *                             relative path
+     */
+    private NodeId getNodeId(Path p) throws RepositoryException {
+        if (p.getLength() == 1) {
+            Path.Element pe = p.getNameElement();
+            if (pe.denotesName()) {
+                // check if node entry exists
+                NodeState thisState = data.getNodeState();
+                int index = pe.getIndex();
+                if (index == 0) {
+                    index = 1;
+                }
+                ChildNodeEntry cne =
+                        thisState.getChildNodeEntry(pe.getName(), index);
+                if (cne != null) {
+                    return cne.getId();
+                } else {
+                    // there's no child node with that name
+                    return null;
+                }
+            }
+        }
+        /**
+         * build and resolve absolute path
+         */
+        p = PathFactoryImpl.getInstance().create(getPrimaryPath(), p, true);
+        return session.getHierarchyManager().resolveNodePath(p);
+    }
+
+    /**
      * Determines if there are pending unsaved changes either on <i>this</i>
      * node or on any node or property in the subtree below it.
      *
@@ -251,7 +281,7 @@
         if (isTransient()) {
             return true;
         }
-        Iterator iter = stateMgr.getDescendantTransientItemStates((NodeId) id);
+        Iterator<ItemState> iter = stateMgr.getDescendantTransientItemStates((NodeId) id);
         return iter.hasNext();
     }
 
@@ -300,6 +330,7 @@
 
         // compute system generated values
         NodeTypeImpl nt = (NodeTypeImpl) def.getDeclaringNodeType();
+        // TODO JCR-2116: Built-In Node Types; => adapt to JCR 2.0 built-in node types (mix:created, etc)
         if (nt.getQName().equals(NameConstants.MIX_REFERENCEABLE)) {
             // mix:referenceable node type
             if (name.equals(NameConstants.JCR_UUID)) {
@@ -327,7 +358,8 @@
                genValues = new InternalValue[]{InternalValue.create(new UUID(hist.getRootVersion().getUUID()))};
            }
 */
-        } else if (nt.getQName().equals(NameConstants.NT_HIERARCHYNODE)) {
+        } else if (nt.getQName().equals(NameConstants.NT_HIERARCHYNODE)
+                || nt.getQName().equals(NameConstants.MIX_CREATED)) {
             // nt:hierarchyNode node type
             if (name.equals(NameConstants.JCR_CREATED)) {
                 // jcr:created property
@@ -352,13 +384,12 @@
                 genValues = new InternalValue[]{InternalValue.create(thisState.getNodeTypeName())};
             } else if (name.equals(NameConstants.JCR_MIXINTYPES)) {
                 // jcr:mixinTypes property
-                Set mixins = thisState.getMixinTypeNames();
-                ArrayList values = new ArrayList(mixins.size());
-                Iterator iter = mixins.iterator();
-                while (iter.hasNext()) {
-                    values.add(InternalValue.create((Name) iter.next()));
+                Set<Name> mixins = thisState.getMixinTypeNames();
+                ArrayList<InternalValue> values = new ArrayList<InternalValue>(mixins.size());
+                for (Name n : mixins) {
+                    values.add(InternalValue.create(n));
                 }
-                genValues = (InternalValue[]) values.toArray(new InternalValue[values.size()]);
+                genValues = values.toArray(new InternalValue[values.size()]);
             }
         }
 
@@ -653,11 +684,11 @@
         if (thisState.hasChildNodeEntries()) {
             // remove child nodes
             // use temp array to avoid ConcurrentModificationException
-            ArrayList tmp = new ArrayList(thisState.getChildNodeEntries());
+            ArrayList<ChildNodeEntry> tmp = new ArrayList<ChildNodeEntry>(thisState.getChildNodeEntries());
             // remove from tail to avoid problems with same-name siblings
             for (int i = tmp.size() - 1; i >= 0; i--) {
                 ChildNodeEntry entry =
-                        (ChildNodeEntry) tmp.get(i);
+                        tmp.get(i);
                 // recursively remove child node
                 NodeId childId = entry.getId();
                 //NodeImpl childNode = (NodeImpl) itemMgr.getItem(childId);
@@ -670,9 +701,8 @@
 
         // remove properties
         // use temp set to avoid ConcurrentModificationException
-        HashSet tmp = new HashSet(thisState.getPropertyNames());
-        for (Iterator iter = tmp.iterator(); iter.hasNext();) {
-            Name propName = (Name) iter.next();
+        HashSet<Name> tmp = new HashSet<Name>(thisState.getPropertyNames());
+        for (Name propName : tmp) {
             // remove the property entry
             thisState.removePropertyName(propName);
             // remove property
@@ -758,12 +788,18 @@
             throw new RepositoryException(msg, e);
         }
 
+        Name nodeTypeName = null;
+        if (nodeType != null) {
+            nodeTypeName = nodeType.getQName();
+            if (nodeType.isMixin()) {
+                throw new ConstraintViolationException(session.getJCRName(nodeTypeName) + ": not a primary node type.");
+            }
+            if (nodeType.isAbstract()) {
+                throw new ConstraintViolationException(session.getJCRName(nodeTypeName)  + ": is an abstract node type.");
+            }
+        }
         NodeDefinitionImpl def;
         try {
-            Name nodeTypeName = null;
-            if (nodeType != null) {
-                nodeTypeName = nodeType.getQName();
-            }
             def = getApplicableChildNodeDefinition(nodeName, nodeTypeName);
         } catch (RepositoryException re) {
             String msg = "no definition found in parent node's node type for new node";
@@ -796,15 +832,15 @@
         }
 
         // check protected flag of parent (i.e. this) node and retention/hold
-        int options = ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD |
-                ItemValidator.CHECK_RETENTION;
+        int options = ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD
+                | ItemValidator.CHECK_RETENTION;
         session.getValidator().checkModify(this, options, Permission.NONE);
 
         // now do create the child node
         return createChildNode(nodeName, def, nodeType, id);
     }
 
-    private void setMixinTypesProperty(Set mixinNames) throws RepositoryException {
+    private void setMixinTypesProperty(Set<Name> mixinNames) throws RepositoryException {
         NodeState thisState = data.getNodeState();
         // get or create jcr:mixinTypes property
         PropertyImpl prop;
@@ -826,10 +862,10 @@
         // call internalSetValue for setting the jcr:mixinTypes property
         // to avoid checking of the 'protected' flag
         InternalValue[] vals = new InternalValue[mixinNames.size()];
-        Iterator iter = mixinNames.iterator();
+        Iterator<Name> iter = mixinNames.iterator();
         int cnt = 0;
         while (iter.hasNext()) {
-            vals[cnt++] = InternalValue.create((Name) iter.next());
+            vals[cnt++] = InternalValue.create(iter.next());
         }
         prop.internalSetValue(vals, PropertyType.NAME);
     }
@@ -839,7 +875,7 @@
      *
      * @return a set of the <code>Name</code>s of this node's mixin types.
      */
-    public Set getMixinTypeNames() {
+    public Set<Name> getMixinTypeNames() {
         return data.getNodeState().getMixinTypeNames();
     }
 
@@ -1005,8 +1041,8 @@
         // check state of this instance
         sanityCheck();
 
-        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
-                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING
+                | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
         int permissions = Permission.NODE_TYPE_MNGMT;
         // special handling of mix:(simple)versionable. since adding the mixin alters
         // the version storage jcr:versionManagement privilege is required
@@ -1035,7 +1071,7 @@
         EffectiveNodeType entExisting;
         try {
             // existing mixin's
-            Set mixins = new HashSet(data.getNodeState().getMixinTypeNames());
+            Set<Name> mixins = new HashSet<Name>(data.getNodeState().getMixinTypeNames());
 
             // build effective node type representing primary type including existing mixin's
             entExisting = ntReg.getEffectiveNodeType(primaryTypeName, mixins);
@@ -1058,7 +1094,7 @@
             // modify the state of this node
             NodeState thisState = (NodeState) getOrCreateTransientItemState();
             // add mixin name
-            Set mixins = new HashSet(thisState.getMixinTypeNames());
+            Set<Name> mixins = new HashSet<Name>(thisState.getMixinTypeNames());
             mixins.add(mixinName);
             thisState.setMixinTypeNames(mixins);
 
@@ -1111,8 +1147,8 @@
         // check state of this instance
         sanityCheck();
 
-        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
-                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING
+                | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
         int permissions = Permission.NODE_TYPE_MNGMT;
         session.getValidator().checkModify(this, options, permissions);
 
@@ -1126,13 +1162,13 @@
         NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
 
         // build effective node type of remaining mixin's & primary type
-        Set remainingMixins = new HashSet(state.getMixinTypeNames());
+        Set<Name> remainingMixins = new HashSet<Name>(state.getMixinTypeNames());
         // remove name of target mixin
         remainingMixins.remove(mixinName);
-        EffectiveNodeType entRemaining;
+        EffectiveNodeType entResulting;
         try {
             // build effective node type representing primary type including remaining mixin's
-            entRemaining = ntReg.getEffectiveNodeType(
+            entResulting = ntReg.getEffectiveNodeType(
                     state.getNodeTypeName(), remainingMixins);
         } catch (NodeTypeConflictException e) {
             throw new ConstraintViolationException(e.getMessage(), e);
@@ -1146,7 +1182,7 @@
         NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
         if ((NameConstants.MIX_REFERENCEABLE.equals(mixinName)
                 || mixin.isDerivedFrom(NameConstants.MIX_REFERENCEABLE))
-                && !entRemaining.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
+                && !entResulting.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
             // removing this mixin would effectively remove mix:referenceable:
             // make sure no references exist
             PropertyIterator iter = getReferences();
@@ -1162,7 +1198,7 @@
          */
         if ((NameConstants.MIX_LOCKABLE.equals(mixinName)
                 || mixin.isDerivedFrom(NameConstants.MIX_LOCKABLE))
-                && !entRemaining.includesNodeType(NameConstants.MIX_LOCKABLE)
+                && !entResulting.includesNodeType(NameConstants.MIX_LOCKABLE)
                 && isLocked()) {
             throw new ConstraintViolationException(mixinName + " can not be removed: the node is locked.");
         }
@@ -1183,39 +1219,103 @@
             return;
         }
 
-        // walk through properties and child nodes and remove those that have
-        // been defined by the specified mixin type
+        // walk through properties and child nodes and remove those that aren't
+        // accomodated by the resulting new effective node type (see JCR-2130)
         boolean success = false;
         try {
             // use temp set to avoid ConcurrentModificationException
-            HashSet set = new HashSet(thisState.getPropertyNames());
-            for (Iterator iter = set.iterator(); iter.hasNext();) {
-                Name propName = (Name) iter.next();
+            HashSet<Name> set = new HashSet<Name>(thisState.getPropertyNames());
+            for (Name propName : set) {
                 PropertyState propState = (PropertyState) stateMgr.getItemState(new PropertyId(thisState.getNodeId(), propName));
                 // check if property has been defined by mixin type (or one of its supertypes)
                 PropertyDefinition def = ntMgr.getPropertyDefinition(propState.getDefinitionId());
                 NodeTypeImpl declaringNT = (NodeTypeImpl) def.getDeclaringNodeType();
-                if (!entRemaining.includesNodeType(declaringNT.getQName())) {
-                    // the remaining effective node type doesn't include the
-                    // node type that declared this property, it is thus safe
-                    // to remove it
-                    removeChildProperty(propName);
+                if (!entResulting.includesNodeType(declaringNT.getQName())) {
+                    // the resulting effective node type doesn't include the
+                    // node type that declared this property
+
+                    // try to find new applicable definition first and
+                    // redefine property if possible (JCR-2130)
+                    try {
+                        PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
+                        if (prop.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected properties immediately
+                            removeChildProperty(propName);
+                            continue;
+                        }
+                        PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(
+                                propName, propState.getType(),
+                                propState.isMultiValued(), false);
+                        if (pdi.getRequiredType() != PropertyType.UNDEFINED
+                                && pdi.getRequiredType() != propState.getType()) {
+                            // value conversion required
+                            if (propState.isMultiValued()) {
+                                // convert value
+                                Value[] values =
+                                        ValueHelper.convert(
+                                                prop.getValues(),
+                                                pdi.getRequiredType(),
+                                                session.getValueFactory());
+                                // redefine property
+                                prop.onRedefine(pdi.unwrap().getId());
+                                // set converted values
+                                prop.setValue(values);
+                            } else {
+                                // convert value
+                                Value value =
+                                        ValueHelper.convert(
+                                                prop.getValue(),
+                                                pdi.getRequiredType(),
+                                                session.getValueFactory());
+                                // redefine property
+                                prop.onRedefine(pdi.unwrap().getId());
+                                // set converted values
+                                prop.setValue(value);
+                            }
+                        } else {
+                            // redefine property
+                            prop.onRedefine(pdi.unwrap().getId());
+                        }
+                    } catch (ValueFormatException vfe) {
+                        // value conversion failed, remove it
+                        removeChildProperty(propName);
+                    } catch (ConstraintViolationException cve) {
+                        // no suitable definition found for this property,
+                        // remove it
+                        removeChildProperty(propName);
+                    }
                 }
             }
             // use temp array to avoid ConcurrentModificationException
-            ArrayList list = new ArrayList(thisState.getChildNodeEntries());
+            ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(thisState.getChildNodeEntries());
             // start from tail to avoid problems with same-name siblings
             for (int i = list.size() - 1; i >= 0; i--) {
-                ChildNodeEntry entry = (ChildNodeEntry) list.get(i);
+                ChildNodeEntry entry = list.get(i);
                 NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
                 NodeDefinition def = ntMgr.getNodeDefinition(nodeState.getDefinitionId());
                 // check if node has been defined by mixin type (or one of its supertypes)
                 NodeTypeImpl declaringNT = (NodeTypeImpl) def.getDeclaringNodeType();
-                if (!entRemaining.includesNodeType(declaringNT.getQName())) {
-                    // the remaining effective node type doesn't include the
-                    // node type that declared this child node, it is thus safe
-                    // to remove it
-                    removeChildNode(entry.getName(), entry.getIndex());
+                if (!entResulting.includesNodeType(declaringNT.getQName())) {
+                    // the resulting effective node type doesn't include the
+                    // node type that declared this child node
+
+                    try {
+                        NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
+                        if (node.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected child node immediately
+                            removeChildNode(entry.getName(), entry.getIndex());
+                            continue;
+                        }
+                        NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(
+                                entry.getName(),
+                                nodeState.getNodeTypeName());
+                        // redefine node
+                        node.onRedefine(ndi.unwrap().getId());
+                    } catch (ConstraintViolationException cve) {
+                        // no suitable definition found for this child node,
+                        // remove it
+                        removeChildNode(entry.getName(), entry.getIndex());
+                    }
                 }
             }
             success = true;
@@ -1245,7 +1345,7 @@
         if (ntName.equals(primary)) {
             return true;
         }
-        Set mixins = data.getNodeState().getMixinTypeNames();
+        Set<Name> mixins = data.getNodeState().getMixinTypeNames();
         if (mixins.contains(ntName)) {
             return true;
         }
@@ -1396,7 +1496,7 @@
      * Returns the child node of <code>this</code> node with the specified
      * <code>name</code>.
      *
-     * @param name The qualified name of the child node to retrieve.
+     * @param name The name of the child node to retrieve.
      * @return The child node with the specified <code>name</code>.
      * @throws ItemNotFoundException If no child node exists with the
      *                               specified name.
@@ -1410,7 +1510,7 @@
      * Returns the child node of <code>this</code> node with the specified
      * <code>name</code>.
      *
-     * @param name  The qualified name of the child node to retrieve.
+     * @param name The name of the child node to retrieve.
      * @param index The index of the child node to retrieve (in the case of same-name siblings).
      * @return The child node with the specified <code>name</code>.
      * @throws ItemNotFoundException If no child node exists with the
@@ -1442,7 +1542,7 @@
      * Returns <code>true</code> if the child node exists and <code>false</code>
      * otherwise.
      *
-     * @param name The qualified name of the child node.
+     * @param name The name of the child node.
      * @return <code>true</code> if the child node exists; <code>false</code> otherwise.
      * @throws RepositoryException If an unspecified error occurs.
      */
@@ -1455,7 +1555,7 @@
      * Returns <code>true</code> if the child node exists and <code>false</code>
      * otherwise.
      *
-     * @param name  The qualified name of the child node.
+     * @param name The name of the child node.
      * @param index The index of the child node (in the case of same-name siblings).
      * @return <code>true</code> if the child node exists; <code>false</code> otherwise.
      * @throws RepositoryException If an unspecified error occurs.
@@ -1479,7 +1579,7 @@
      * Returns the property of <code>this</code> node with the specified
      * <code>name</code>.
      *
-     * @param name The qualified name of the property to retrieve.
+     * @param name The name of the property to retrieve.
      * @return The property with the specified <code>name</code>.
      * @throws ItemNotFoundException If no property exists with the
      *                               specified name.
@@ -1503,7 +1603,7 @@
      * Returns <code>true</code> if the property exists and <code>false</code>
      * otherwise.
      *
-     * @param name The qualified name of the property.
+     * @param name The name of the property.
      * @return <code>true</code> if the property exists; <code>false</code> otherwise.
      * @throws RepositoryException If an unspecified error occurs.
      */
@@ -1781,14 +1881,14 @@
         }
 
         // make sure this node is checked-out and neither protected nor locked
-        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
-                ItemValidator.CHECK_CONSTRAINTS;
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING
+                | ItemValidator.CHECK_CONSTRAINTS;
         session.getValidator().checkModify(this, options, Permission.NONE);
 
-        ArrayList list = new ArrayList(data.getNodeState().getChildNodeEntries());
+        ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(data.getNodeState().getChildNodeEntries());
         int srcInd = -1, destInd = -1;
         for (int i = 0; i < list.size(); i++) {
-            ChildNodeEntry entry = (ChildNodeEntry) list.get(i);
+            ChildNodeEntry entry = list.get(i);
             if (srcInd == -1) {
                 if (entry.getName().equals(srcName.getName())
                         && (entry.getIndex() == srcName.getIndex()
@@ -1881,7 +1981,7 @@
             throw new ItemNotFoundException(
                     this + ": no child node entry with id " + id);
         }
-        List cneList = new ArrayList(state.getChildNodeEntries());
+        List<ChildNodeEntry> cneList = new ArrayList<ChildNodeEntry>(state.getChildNodeEntries());
 
         // remove existing
         existing.remove();
@@ -1905,8 +2005,7 @@
             // replace child node entry with different name
             // but preserving original position
             state.removeAllChildNodeEntries();
-            for (Iterator iter = cneList.iterator(); iter.hasNext();) {
-                ChildNodeEntry cne = (ChildNodeEntry) iter.next();
+            for (ChildNodeEntry cne : cneList) {
                 if (cne.getId().equals(id)) {
                     // replace entry with different name
                     state.addChildNodeEntry(nodeName, id);
@@ -2075,10 +2174,6 @@
         sanityCheck();
 
         NodeTypeImpl nt = (NodeTypeImpl) session.getNodeTypeManager().getNodeType(nodeTypeName);
-        if (nt.isMixin()) {
-            throw new RepositoryException(nodeTypeName + ": not a primary node type");
-        }
-
         return internalAddNode(relPath, nt);
     }
 
@@ -2558,17 +2653,28 @@
      */
     public Node getNode(String relPath)
             throws PathNotFoundException, RepositoryException {
+
         // check state of this instance
         sanityCheck();
-        NodeId id = resolveRelativeNodePath(relPath);
+
+        Path p = resolveRelativePath(relPath);
+        NodeId id = getNodeId(p);
         if (id == null) {
             throw new PathNotFoundException(relPath);
         }
+
+        // determine parent as mandated by path
+        NodeId parentId = null;
+        if (!p.denotesRoot()) {
+            parentId = getNodeId(p.getAncestor(1));
+        }
         try {
-            if (data.getNodeState().hasChildNodeEntry(id)) {
-                return itemMgr.getNode(id, getNodeId());
-            }
-            return (NodeImpl) itemMgr.getItem(id);
+            if (parentId == null) {
+                return (NodeImpl) itemMgr.getItem(id);
+            }
+            // if the node is shareable, it now returns the node with the right
+            // parent
+            return itemMgr.getNode(id, parentId);
         } catch (AccessDeniedException ade) {
             throw new PathNotFoundException(relPath);
         } catch (ItemNotFoundException infe) {
@@ -2728,15 +2834,15 @@
         // check state of this instance
         sanityCheck();
 
-        Set mixinNames = data.getNodeState().getMixinTypeNames();
+        Set<Name> mixinNames = data.getNodeState().getMixinTypeNames();
         if (mixinNames.isEmpty()) {
             return new NodeType[0];
         }
         NodeType[] nta = new NodeType[mixinNames.size()];
-        Iterator iter = mixinNames.iterator();
+        Iterator<Name> iter = mixinNames.iterator();
         int i = 0;
         while (iter.hasNext()) {
-            nta[i++] = session.getNodeTypeManager().getNodeType((Name) iter.next());
+            nta[i++] = session.getNodeTypeManager().getNodeType(iter.next());
         }
         return nta;
     }
@@ -2783,15 +2889,15 @@
         if (!mixin.isMixin()) {
             return false;
         }
-        
-        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
-                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING
+                | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
         int permissions = Permission.NODE_TYPE_MNGMT;
         // special handling of mix:(simple)versionable. since adding the mixin alters
         // the version storage jcr:versionManagement privilege is required
         // in addition.
         if (NameConstants.MIX_VERSIONABLE.equals(ntName)
-                || NameConstants.MIX_SIMPLE_VERSIONABLE.equals(mixinName)) {
+                || NameConstants.MIX_SIMPLE_VERSIONABLE.equals(ntName)) {
             permissions |= Permission.VERSION_MNGMT;
         }
         if (!session.getValidator().canModify(this, options, permissions)) {
@@ -2802,7 +2908,8 @@
 
         NodeTypeImpl primaryType = ntMgr.getNodeType(primaryTypeName);
         if (primaryType.isDerivedFrom(ntName)) {
-            return false;
+            // mixin already inherited -> addMixin is allowed but has no effect.
+            return true;
         }
 
         // build effective node type of mixins & primary type
@@ -2811,12 +2918,14 @@
         EffectiveNodeType entExisting;
         try {
             // existing mixin's
-            Set mixins = new HashSet(data.getNodeState().getMixinTypeNames());
+            Set<Name> mixins = new HashSet<Name>(data.getNodeState().getMixinTypeNames());
 
             // build effective node type representing primary type including existing mixin's
             entExisting = ntReg.getEffectiveNodeType(primaryTypeName, mixins);
             if (entExisting.includesNodeType(ntName)) {
-                return false;
+                // the existing mixins already include the mixin to be added.
+                // addMixin would succeed without modifying the node.
+                return true;
             }
 
             // add new mixin
@@ -2949,7 +3058,7 @@
             // if root is common ancestor, corresponding path is same as ours
             if (m1.getDepth() == 0) {
                 // check existence
-                if (!srcSession.getItemManager().itemExists(getPrimaryPath())) {
+                if (!srcSession.getItemManager().nodeExists(getPrimaryPath())) {
                     throw new ItemNotFoundException("Node not found: " + this);
                 } else {
                     return getPath();
@@ -3031,15 +3140,13 @@
         // check state of this instance
         sanityCheck();
 
-        ArrayList list = new ArrayList();
+        ArrayList<NodeImpl> list = new ArrayList<NodeImpl>();
 
         if (!isShareable()) {
             list.add(this);
         } else {
             NodeState state = data.getNodeState();
-            Iterator iter = state.getSharedSet().iterator();
-            while (iter.hasNext()) {
-                NodeId parentId = (NodeId) iter.next();
+            for (NodeId parentId : state.getSharedSet()) {
                 list.add(itemMgr.getNode(getNodeId(), parentId));
             }
         }
@@ -3072,7 +3179,7 @@
 
         NodeIterator iter = getSharedSet();
         while (iter.hasNext()) {
-            ((NodeImpl) iter.nextNode()).removeShare();
+            iter.nextNode().removeShare();
         }
     }
 
@@ -3251,6 +3358,9 @@
             if (isFull) {
                 internalSetProperty(NameConstants.JCR_BASEVERSION, InternalValue.create(new UUID(v.getUUID())));
                 internalSetProperty(NameConstants.JCR_PREDECESSORS, InternalValue.EMPTY_ARRAY, PropertyType.REFERENCE);
+                if (hasProperty(NameConstants.JCR_ACTIVITY)) {
+                    removeChildProperty(NameConstants.JCR_ACTIVITY);
+                }
             }
             save();
             success = true;
@@ -3291,20 +3401,26 @@
         session.getValidator().checkModify(this, options, Permission.VERSION_MNGMT);
 
         boolean hasPendingChanges = hasPendingChanges();
-        Property[] props = new Property[2];
+        Property[] props = new Property[3];
         boolean success = false;
         try {
             props[0] = internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(true));
             if (isFull) {
+                NodeImpl activity = (NodeImpl) session.getWorkspace().getVersionManager().getActivity();
+                Version baseVersion = session.getVersionManager().checkout(this);
                 props[1] = internalSetProperty(NameConstants.JCR_PREDECESSORS,
                         new InternalValue[]{
-                                InternalValue.create(new UUID(getBaseVersion().getUUID()))
+                                InternalValue.create(new UUID(baseVersion.getUUID()))
                         });
+                if (activity != null) {
+                    props[2] = internalSetProperty(NameConstants.JCR_ACTIVITY,
+                            InternalValue.create(activity.getNodeId().getUUID()));
+                }
             }
             if (hasPendingChanges) {
-                for (int i = 0; i < props.length; i++) {
-                    if (props[i] != null) {
-                        props[i].save();
+                for (Property prop : props) {
+                    if (prop != null) {
+                        prop.save();
                     }
                 }
             } else {
@@ -3313,10 +3429,10 @@
             success = true;
         } finally {
             if (!success) {
-                for (int i = 0; i < props.length; i++) {
-                    if (props[i] != null) {
+                for (Property prop : props) {
+                    if (prop != null) {
                         try {
-                            props[i].refresh(false);
+                            prop.refresh(false);
                         } catch (RepositoryException e) {
                             log.error("Error while cleaning up after failed Node.checkout", e);
                         }
@@ -3359,6 +3475,9 @@
         return new LazyItemIterator(itemMgr, failedIds);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public void cancelMerge(Version version)
             throws VersionException, InvalidItemStateException,
             UnsupportedRepositoryOperationException, RepositoryException {
@@ -3414,7 +3533,7 @@
         // do checks
         sanityCheck();
         checkVersionable();
-        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK| ItemValidator.CHECK_HOLD;
+        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD;
         session.getValidator().checkModify(this, options, Permission.NONE);
 
         // check if 'own' version
@@ -3485,7 +3604,7 @@
 
         // do checks
         sanityCheck();
-        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK| ItemValidator.CHECK_HOLD;
+        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD;
         session.getValidator().checkModify(this, options, Permission.NONE);
 
         Version v = getVersionHistory().getVersionByLabel(versionLabel);
@@ -3583,8 +3702,7 @@
      *         node exists.
      * @throws RepositoryException If another error occurs.
      */
-    private NodeImpl getCorrespondingNode(SessionImpl srcSession)
-            throws AccessDeniedException, RepositoryException {
+    private NodeImpl getCorrespondingNode(SessionImpl srcSession) throws RepositoryException {
 
         // search nearest ancestor that is referenceable
         NodeImpl m1 = this;
@@ -3675,7 +3793,7 @@
      * @throws RepositoryException if an error occurs.
      * @throws AccessDeniedException if access is denied
      */
-    private NodeImpl doMergeTest(SessionImpl srcSession, List failedIds, boolean bestEffort)
+    private NodeImpl doMergeTest(SessionImpl srcSession, List<ItemId> failedIds, boolean bestEffort)
             throws RepositoryException, AccessDeniedException {
 
         // If N does not have a corresponding node then the merge result for N is leave.
@@ -3713,7 +3831,7 @@
             // thus determining the result of a merge is non-trivial.
             if (bestEffort) {
                 // add 'offending' version to jcr:mergeFailed property
-                Set set = internalGetMergeFailed();
+                Set<String> set = internalGetMergeFailed();
                 set.add(srcNode.getBaseVersion().getUUID());
                 internalSetMergeFailed(set);
                 failedIds.add(id);
@@ -3745,7 +3863,7 @@
         session.getValidator().checkModify(this, options, Permission.VERSION_MNGMT);
 
         // check if version is in mergeFailed list
-        Set failed = internalGetMergeFailed();
+        Set<String> failed = internalGetMergeFailed();
         if (!failed.remove(version.getUUID())) {
             String msg =
                 "Unable to finish merge. Specified version is not in"
@@ -3787,8 +3905,8 @@
      * @return
      * @throws RepositoryException
      */
-    private Set internalGetMergeFailed() throws RepositoryException {
-        HashSet set = new HashSet();
+    private Set<String> internalGetMergeFailed() throws RepositoryException {
+        HashSet<String> set = new HashSet<String>();
         if (hasProperty(NameConstants.JCR_MERGEFAILED)) {
             Value[] vals = getProperty(NameConstants.JCR_MERGEFAILED).getValues();
             for (int i = 0; i < vals.length; i++) {
@@ -3802,15 +3920,15 @@
      * @param set
      * @throws RepositoryException
      */
-    private void internalSetMergeFailed(Set set) throws RepositoryException {
+    private void internalSetMergeFailed(Set<String> set) throws RepositoryException {
         if (set.isEmpty()) {
             internalSetProperty(NameConstants.JCR_MERGEFAILED, (InternalValue[]) null);
         } else {
             InternalValue[] vals = new InternalValue[set.size()];
-            Iterator iter = set.iterator();
+            Iterator<String> iter = set.iterator();
             int i = 0;
             while (iter.hasNext()) {
-                String uuid = (String) iter.next();
+                String uuid = iter.next();
                 vals[i++] = InternalValue.create(UUID.fromString(uuid));
             }
             internalSetProperty(NameConstants.JCR_MERGEFAILED, vals);
@@ -3900,8 +4018,8 @@
         // get frozen mixin
         // todo: also respect mixing types on creation?
         Name[] mxNames = frozen.getFrozenMixinTypes();
-        for (int i = 0; i < mxNames.length; i++) {
-            node.addMixin(mxNames[i]);
+        for (Name mxName : mxNames) {
+            node.addMixin(mxName);
         }
         return node;
     }
@@ -3944,8 +4062,8 @@
         // get frozen mixin
         // todo: also respect mixing types on creation?
         Name[] mxNames = frozen.getFrozenMixinTypes();
-        for (int i = 0; i < mxNames.length; i++) {
-            node.addMixin(mxNames[i]);
+        for (Name mxName : mxNames) {
+            node.addMixin(mxName);
         }
         return node;
     }
@@ -3966,7 +4084,7 @@
      * @throws RepositoryException
      */
     private void internalMerge(String srcWorkspaceName,
-                               List failedIds, boolean bestEffort,
+                               List<ItemId> failedIds, boolean bestEffort,
                                boolean shallow)
             throws NoSuchWorkspaceException, AccessDeniedException,
             LockException, InvalidItemStateException, RepositoryException {
@@ -4019,7 +4137,7 @@
      * @throws LockException
      * @throws RepositoryException
      */
-    private void internalMerge(SessionImpl srcSession, List failedIds,
+    private void internalMerge(SessionImpl srcSession, List<ItemId> failedIds,
                                boolean bestEffort, boolean removeExisting,
                                boolean replaceExisting, boolean shallow)
             throws LockException, RepositoryException {
@@ -4143,15 +4261,14 @@
     /**
      * Internal method to restore a version.
      *
-     * @param version
-     * @param vsel    the version selector that will select the correct version for
-     *                OPV=Version child nodes.
-     * @throws UnsupportedRepositoryOperationException
-     *
-     * @throws RepositoryException
+     * @param version version to restore
+     * @param vsel the version selector that will select the correct version for
+     * OPV=Version child nodes.
+     * @param removeExisting remove existing flag
+     * @throws RepositoryException if an error occurs
      */
     private void internalRestore(Version version, VersionSelector vsel, boolean removeExisting)
-            throws UnsupportedRepositoryOperationException, RepositoryException {
+            throws RepositoryException {
 
         boolean success = false;
         try {
@@ -4174,13 +4291,14 @@
     /**
      * Internal method to restore a version.
      *
-     * @param version
-     * @param vsel           the version selector that will select the correct version for
-     *                       OPV=Version child nodes.
-     * @param removeExisting
-     * @throws RepositoryException
+     * @param version version to restore
+     * @param vsel the version selector that will select the correct version for
+     * OPV=Version child nodes.
+     * @param removeExisting remove existing flag
+     * @return array of restored versions
+     * @throws RepositoryException if an error occurs
      */
-    protected Version[] internalRestore(VersionImpl version, VersionSelector vsel,
+    public Version[] internalRestore(VersionImpl version, VersionSelector vsel,
                                         boolean removeExisting)
             throws RepositoryException {
 
@@ -4200,7 +4318,7 @@
         // 1. The child node and properties of N will be changed, removed or
         //    added to, depending on their corresponding copies in V and their
         //    own OnParentVersion attributes (see 7.2.8, below, for details).
-        HashSet restored = new HashSet();
+        HashSet<Version> restored = new HashSet<Version>();
         restoreFrozenState(version.getInternalFrozenNode(), vsel, restored, removeExisting);
         restored.add(version);
 
@@ -4223,18 +4341,20 @@
         // 3. N's jcr:isCheckedOut property is set to false.
         internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(false));
 
-        return (Version[]) restored.toArray(new Version[restored.size()]);
+        return restored.toArray(new Version[restored.size()]);
     }
 
     /**
      * Restores the properties and child nodes from the frozen state.
      *
-     * @param freeze
-     * @param vsel
-     * @param removeExisting
-     * @throws RepositoryException
+     * @param freeze the frozen node
+     * @param vsel version selector
+     * @param restored set of restored versions
+     * @param removeExisting remove existing flag
+     * @throws RepositoryException if an error occurs
      */
-    void restoreFrozenState(InternalFrozenNode freeze, VersionSelector vsel, Set restored, boolean removeExisting)
+    public void restoreFrozenState(InternalFrozenNode freeze, VersionSelector vsel,
+                            Set<Version> restored, boolean removeExisting)
             throws RepositoryException {
 
         // check uuid
@@ -4253,19 +4373,22 @@
 
         // adjust mixins
         Name[] mixinNames = freeze.getFrozenMixinTypes();
-        setMixinTypesProperty(new HashSet(Arrays.asList(mixinNames)));
+        setMixinTypesProperty(new HashSet<Name>(Arrays.asList(mixinNames)));
 
         // copy frozen properties
         PropertyState[] props = freeze.getFrozenProperties();
-        HashSet propNames = new HashSet();
-        for (int i = 0; i < props.length; i++) {
-            PropertyState prop = props[i];
+        HashSet<Name> propNames = new HashSet<Name>();
+        for (PropertyState prop : props) {
+            // skip properties that should not to be reverted back
+            if (prop.getName().equals(NameConstants.JCR_ACTIVITY)) {
+                continue;
+            }
             propNames.add(prop.getName());
             if (prop.isMultiValued()) {
                 internalSetProperty(
-                        props[i].getName(), prop.getValues(), prop.getType());
+                        prop.getName(), prop.getValues(), prop.getType());
             } else {
-                internalSetProperty(props[i].getName(), prop.getValues()[0]);
+                internalSetProperty(prop.getName(), prop.getValues()[0]);
             }
         }
         // remove properties that do not exist in the frozen representation
@@ -4288,11 +4411,11 @@
 
         // add 'auto-create' properties that do not exist yet
         NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
-        for (int j = 0; j < mixinNames.length; j++) {
-            NodeTypeImpl mixin = ntMgr.getNodeType(mixinNames[j]);
+        for (Name mixinName : mixinNames) {
+            NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
             PropertyDefinition[] pda = mixin.getAutoCreatedPropertyDefinitions();
-            for (int i = 0; i < pda.length; i++) {
-                PropertyDefinitionImpl pd = (PropertyDefinitionImpl) pda[i];
+            for (PropertyDefinition aPda : pda) {
+                PropertyDefinitionImpl pd = (PropertyDefinitionImpl) aPda;
                 if (!hasProperty(pd.getQName())) {
                     createChildProperty(pd.getQName(), pd.getRequiredType(), pd);
                 }
@@ -4320,8 +4443,7 @@
 
         // restore the frozen nodes
         InternalFreeze[] frozenNodes = freeze.getFrozenChildNodes();
-        for (int i = 0; i < frozenNodes.length; i++) {
-            InternalFreeze child = frozenNodes[i];
+        for (InternalFreeze child : frozenNodes) {
             NodeImpl restoredChild = null;
             if (child instanceof InternalFrozenNode) {
                 InternalFrozenNode f = (InternalFrozenNode) child;
@@ -4329,7 +4451,7 @@
                 if (f.getFrozenUUID() != null) {
                     try {
                         NodeImpl existing = (NodeImpl) session.getNodeByUUID(f.getFrozenUUID());
-                        // check if one of this restoretrees node
+                        // check if one of this restore trees node
                         if (removeExisting) {
                             existing.remove();
                         } else if (existing.isShareable()) {
@@ -4340,8 +4462,8 @@
                             // found nodes must be outside of this tree
                             throw new ItemExistsException(
                                     "Unable to restore node, item already"
-                                    + " exists outside of restored tree: "
-                                    + existing);
+                                            + " exists outside of restored tree: "
+                                            + existing);
                         }
                     } catch (ItemNotFoundException e) {
                         // ignore, item with uuid does not exist
@@ -4374,7 +4496,7 @@
                         // found nodes must be outside of this tree
                         throw new ItemExistsException(
                                 "Unable to restore node, item already exists"
-                                + " outside of restored tree: " + n);
+                                        + " outside of restored tree: " + n);
                     }
                 }
                 // get desired version from version selector
@@ -4388,7 +4510,7 @@
                         Version[] vs = history.getRootVersion().getSuccessors();
                         if (vs.length == 0) {
                             String msg = "Unable to select appropariate version for "
-                                + child.getName() + " using " + vsel;
+                                    + child.getName() + " using " + vsel;
                             log.error(msg);
                             throw new VersionException(msg);
                         }
@@ -4424,7 +4546,7 @@
                     restored.add(v);
                 }
             }
-            // ensure proper odering (issue JCR-469)
+            // ensure proper ordering (issue JCR-469)
             if (restoredChild != null
                     && getPrimaryNodeType().hasOrderableChildNodes()) {
                 orderBefore(restoredChild.getPrimaryPath().getNameElement(), null);
@@ -4435,8 +4557,8 @@
     /**
      * Copies a property to this node
      *
-     * @param prop
-     * @throws RepositoryException
+     * @param prop property to copy from
+     * @throws RepositoryException if an error occurs
      */
     protected void internalCopyPropertyFrom(PropertyImpl prop) throws RepositoryException {
         if (prop.getDefinition().isMultiple()) {
@@ -4462,7 +4584,7 @@
             RepositoryException {
         // check state of this instance
         sanityCheck();
-        LockManager lockMgr = ((WorkspaceImpl) session.getWorkspace()).getLockManager();
+        LockManager lockMgr = session.getWorkspace().getLockManager();
         return lockMgr.lock(getPath(), isDeep, isSessionScoped, Long.MAX_VALUE, null);
     }
 
@@ -4474,7 +4596,7 @@
             AccessDeniedException, RepositoryException {
         // check state of this instance
         sanityCheck();
-        LockManager lockMgr = ((WorkspaceImpl) session.getWorkspace()).getLockManager();
+        LockManager lockMgr = session.getWorkspace().getLockManager();
         return lockMgr.getLock(getPath());
     }
 
@@ -4487,7 +4609,7 @@
             RepositoryException {
         // check state of this instance
         sanityCheck();
-        LockManager lockMgr = ((WorkspaceImpl) session.getWorkspace()).getLockManager();
+        LockManager lockMgr = session.getWorkspace().getLockManager();
         lockMgr.unlock(getPath());
     }
 
@@ -4497,7 +4619,7 @@
     public boolean holdsLock() throws RepositoryException {
         // check state of this instance
         sanityCheck();
-        LockManager lockMgr = ((WorkspaceImpl) session.getWorkspace()).getLockManager();
+        LockManager lockMgr = session.getWorkspace().getLockManager();
         return lockMgr.holdsLock(getPath());
     }
 
@@ -4507,7 +4629,7 @@
     public boolean isLocked() throws RepositoryException {
         // check state of this instance
         sanityCheck();
-        LockManager lockMgr = ((WorkspaceImpl) session.getWorkspace()).getLockManager();
+        LockManager lockMgr = session.getWorkspace().getLockManager();
         return lockMgr.isLocked(getPath());
     }
 
@@ -4547,7 +4669,7 @@
             if (stateMgr.hasNodeReferences(targetId)) {
                 NodeReferences refs = stateMgr.getNodeReferences(targetId);
                 // refs.getReferences() returns a list of PropertyId's
-                List idList = refs.getReferences();
+                List<PropertyId> idList = refs.getReferences();
                 if (name != null) {
                     Name qName;
                     try {
@@ -4555,9 +4677,8 @@
                     } catch (NameException e) {
                         throw new RepositoryException("invalid property name: " + name, e);
                     }
-                    ArrayList filteredList = new ArrayList(idList.size());
-                    for (Iterator iter = idList.iterator(); iter.hasNext();) {
-                        PropertyId propId = (PropertyId) iter.next();
+                    ArrayList<PropertyId> filteredList = new ArrayList<PropertyId>(idList.size());
+                    for (PropertyId propId : idList) {
                         if (propId.getName().equals(qName)) {
                             filteredList.add(propId);
                         }
@@ -4580,38 +4701,63 @@
      * {@inheritDoc}
      */
     public PropertyIterator getWeakReferences() throws RepositoryException {
-        return getWeakReferences(null);
+        // check state of this instance
+        sanityCheck();
+
+        // shortcut if node isn't referenceable
+        if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+            return PropertyIteratorAdapter.EMPTY;
+        }
+
+        Value ref = getSession().getValueFactory().createValue(this, true);
+        List<Property> props = new ArrayList<Property>();
+        QueryManagerImpl qm = (QueryManagerImpl) session.getWorkspace().getQueryManager();
+        for (Node n : qm.getWeaklyReferringNodes(this)) {
+            for (PropertyIterator it = n.getProperties(); it.hasNext(); ) {
+                Property p = it.nextProperty();
+                if (p.getType() == PropertyType.WEAKREFERENCE) {
+                    Collection<Value> refs;
+                    if (p.isMultiple()) {
+                        refs = Arrays.asList(p.getValues());
+                    } else {
+                        refs = Collections.singleton(p.getValue());
+                    }
+                    if (refs.contains(ref)) {
+                        props.add(p);
+                    }
+                }
+            }
+        }
+        return new PropertyIteratorAdapter(props);
     }
 
     /**
      * {@inheritDoc}
      */
     public PropertyIterator getWeakReferences(String name) throws RepositoryException {
+        if (name == null) {
+            return getWeakReferences();
+        }
+
         // check state of this instance
         sanityCheck();
 
-        // TODO tweak query implemention in order to support WEAKREFERENCE reverse lookup 
+        // shortcut if node isn't referenceable
+        if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+            return PropertyIteratorAdapter.EMPTY;
+        }
+        
         try {
+            StringBuilder stmt = new StringBuilder();
+            stmt.append("//*[@").append(ISO9075.encode(name));
+            stmt.append(" = '").append(data.getId()).append("']");
             Query q = session.getWorkspace().getQueryManager().createQuery(
-                    "//*[jcr:contains(., '" + data.getId() + "')]",
-                    Query.XPATH);
+                    stmt.toString(), Query.XPATH);
             QueryResult result = q.execute();
-            ArrayList l = new ArrayList<Property>();
-            for (NodeIterator nit = result.getNodes(); nit.hasNext(); ) {
+            ArrayList<Property> l = new ArrayList<Property>();
+            for (NodeIterator nit = result.getNodes(); nit.hasNext();) {
                 Node n = nit.nextNode();
-                for (PropertyIterator pit = n.getProperties(); pit.hasNext(); ) {
-                    Property p = pit.nextProperty();
-                    if (p.getType() == PropertyType.WEAKREFERENCE
-                            && p.getString().equals(getIdentifier())) {
-                        if (name != null) {
-                            if (name.equals(p.getName())) {
-                                l.add(p);
-                            }
-                        } else {
-                            l.add(p);
-                        }
-                    }
-                }
+                l.add(n.getProperty(name));
             }
             if (l.isEmpty()) {
                 return PropertyIteratorAdapter.EMPTY;
@@ -4642,16 +4788,14 @@
     /**
      * {@inheritDoc}
      */
-    // TODO rename method to 'getProperties' once JCR 2.0 api has been fixed
-    public PropertyIterator getProperty(String[]
-            nameGlobs)
+    public PropertyIterator getProperties(String[] nameGlobs)
             throws RepositoryException {
         // check state of this instance
         sanityCheck();
 
         ArrayList props = new ArrayList();
         // traverse children using a special filtering 'collector'
-        accept(new ChildrenCollectorFilter(nameGlobs, props, true, false, 1));
+        accept(new ChildrenCollectorFilter(nameGlobs, props, false, true, 1));
         return new PropertyIteratorAdapter(props);
     }
 
@@ -4666,8 +4810,8 @@
 
         // make sure this node is checked-out, neither protected nor locked and
         // the editing session has sufficient permission to change the primary type.
-        int options = ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_LOCK |
-                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        int options = ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_LOCK
+                | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
         session.getValidator().checkModify(this, options, Permission.NODE_TYPE_MNGMT);
 
         final NodeState state = data.getNodeState();
@@ -4684,8 +4828,11 @@
         }
 
         NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
-        if (ntMgr.getNodeType(ntName).isMixin()) {
-            throw new RepositoryException(nodeTypeName + ": not a primary node type");
+        NodeType nt = ntMgr.getNodeType(ntName);
+        if (nt.isMixin()) {
+            throw new ConstraintViolationException(nodeTypeName + ": not a primary node type.");
+        } else if (nt.isAbstract()) {
+            throw new ConstraintViolationException(nodeTypeName + ": is an abstract node type.");
         }
 
         // build effective node type of new primary type & existing mixin's
@@ -4717,12 +4864,12 @@
             onRedefine(defId);
         }
 
-        Set oldDefs = new HashSet(Arrays.asList(entOld.getAllItemDefs()));
-        Set newDefs = new HashSet(Arrays.asList(entNew.getAllItemDefs()));
-        Set allDefs = new HashSet(Arrays.asList(entAll.getAllItemDefs()));
+        Set<ItemDef> oldDefs = new HashSet<ItemDef>(Arrays.asList(entOld.getAllItemDefs()));
+        Set<ItemDef> newDefs = new HashSet<ItemDef>(Arrays.asList(entNew.getAllItemDefs()));
+        Set<ItemDef> allDefs = new HashSet<ItemDef>(Arrays.asList(entAll.getAllItemDefs()));
 
         // added child item definitions
-        Set addedDefs = new HashSet(newDefs);
+        Set<ItemDef> addedDefs = new HashSet<ItemDef>(newDefs);
         addedDefs.removeAll(oldDefs);
 
         // referential integrity check
@@ -4752,9 +4899,8 @@
         // walk through properties and child nodes and change definition as necessary
 
         // use temp set to avoid ConcurrentModificationException
-        HashSet set = new HashSet(thisState.getPropertyNames());
-        for (Iterator iter = set.iterator(); iter.hasNext();) {
-            Name propName = (Name) iter.next();
+        HashSet<Name> set = new HashSet<Name>(thisState.getPropertyNames());
+        for (Name propName : set) {
             try {
                 PropertyState propState =
                         (PropertyState) stateMgr.getItemState(
@@ -4764,6 +4910,11 @@
                     // redefine property if possible
                     try {
                         PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
+                        if (prop.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected properties immediately
+                            removeChildProperty(propName);
+                            continue;
+                        }
                         PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(
                                 propName, propState.getType(),
                                 propState.isMultiValued(), false);
@@ -4816,21 +4967,26 @@
         }
 
         // use temp array to avoid ConcurrentModificationException
-        ArrayList list = new ArrayList(thisState.getChildNodeEntries());
+        ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(thisState.getChildNodeEntries());
         // start from tail to avoid problems with same-name siblings
         for (int i = list.size() - 1; i >= 0; i--) {
-            ChildNodeEntry entry = (ChildNodeEntry) list.get(i);
+            ChildNodeEntry entry = list.get(i);
             try {
                 NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
                 if (!allDefs.contains(ntReg.getNodeDef(nodeState.getDefinitionId()))) {
                     // try to find new applicable definition first and
                     // redefine node if possible
                     try {
+                        NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
+                        if (node.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected child node immediately
+                            removeChildNode(entry.getName(), entry.getIndex());
+                            continue;
+                        }
                         NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(
                                 entry.getName(),
                                 nodeState.getNodeTypeName());
                         // redefine node
-                        NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
                         node.onRedefine(ndi.unwrap().getId());
                         // update collection of added definitions
                         addedDefs.remove(ndi.unwrap());
@@ -4849,8 +5005,8 @@
 
         // create items that are defined as auto-created by the new primary node
         // type and at the same time were not present with the old nt
-        for (Iterator iter = addedDefs.iterator(); iter.hasNext();) {
-            ItemDef def = (ItemDef) iter.next();
+        for (Iterator<ItemDef> iter = addedDefs.iterator(); iter.hasNext();) {
+            ItemDef def = iter.next();
             if (def.isAutoCreated()) {
                 if (def.definesNode()) {
                     NodeDefinitionImpl ndi = ntMgr.getNodeDefinition(((NodeDef) def).getId());

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyId.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyId.java?rev=792142&r1=792141&r2=792142&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyId.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyId.java Wed Jul  8 13:57:13 2009
@@ -21,7 +21,7 @@
 
 /**
  * Property identifier. An instance of this class identifies a single
- * property using the UUID of the parent node and the qualified name of
+ * property using the UUID of the parent node and the name of
  * the property. Once created a property identifier instance is immutable.
  */
 public class PropertyId extends ItemId {
@@ -32,7 +32,7 @@
     /** id of the parent node. */
     private final NodeId parentId;
 
-    /** Qualified name of the property. */
+    /** Name of the property. */
     private final Name propName;
 
     /** the precalculated hash code */
@@ -42,7 +42,7 @@
      * Creates a property identifier instance for the identified property.
      *
      * @param parentId the id of the parent node
-     * @param propName qualified name of the property
+     * @param propName Name of the property
      */
     public PropertyId(NodeId parentId, Name propName) {
         if (parentId == null) {
@@ -81,9 +81,9 @@
     }
 
     /**
-     * Returns the qualified name of the property.
+     * Returns the <code>Name</code> of the property.
      *
-     * @return qualified name
+     * @return <code>Name</code> of the property.
      */
     public Name getName() {
         return propName;



Mime
View raw message