Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 96260 invoked from network); 8 Jul 2009 13:58:44 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 8 Jul 2009 13:58:44 -0000 Received: (qmail 37621 invoked by uid 500); 8 Jul 2009 13:58:54 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 37591 invoked by uid 500); 8 Jul 2009 13:58:54 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 37582 invoked by uid 99); 8 Jul 2009 13:58:54 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Jul 2009 13:58:54 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Jul 2009 13:58:38 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id BD46D23888E6; Wed, 8 Jul 2009 13:58:16 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: commits@jackrabbit.apache.org From: jukka@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090708135816.BD46D23888E6@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 ItemManager */ - private final Map itemCache; + private final Map 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 childIds = new ArrayList(); + Iterator 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 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 childIds = new ArrayList(); + Iterator 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 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 REPOSITORY_INSTANCES = new HashMap(); + + 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 idList; /** parent node id (when returning children nodes) or null */ 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(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 reservedPrefixes = new HashSet(); + private static final HashSet reservedURIs = new HashSet(); 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 prefixToURI = new HashMap(); + private HashMap uriToPrefix = new HashMap(); - private HashMap indexToURI = new HashMap(); - private HashMap uriToIndex = new HashMap(); + private HashMap indexToURI = new HashMap(); + private HashMap uriToIndex = new HashMap(); - 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 Path. If + * a NameException occurs, it will be rethrown embedded + * into a RepositoryException + * + * @param relPath relative path + * @return Path 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 p or null + * if no node exists at p. + *

+ * Note that access rights are not checked. + * + * @param p relative path of a (possible) node + * @return the id of the node at p or + * null if no node exists at p + * @throws RepositoryException if relPath 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 this * 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 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 mixins = thisState.getMixinTypeNames(); + ArrayList values = new ArrayList(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 tmp = new ArrayList(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 tmp = new HashSet(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 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 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 Names of this node's mixin types. */ - public Set getMixinTypeNames() { + public Set 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 mixins = new HashSet(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 mixins = new HashSet(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 remainingMixins = new HashSet(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 set = new HashSet(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 list = new ArrayList(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 mixins = data.getNodeState().getMixinTypeNames(); if (mixins.contains(ntName)) { return true; } @@ -1396,7 +1496,7 @@ * Returns the child node of this node with the specified * name. * - * @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 name. * @throws ItemNotFoundException If no child node exists with the * specified name. @@ -1410,7 +1510,7 @@ * Returns the child node of this node with the specified * name. * - * @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 name. * @throws ItemNotFoundException If no child node exists with the @@ -1442,7 +1542,7 @@ * Returns true if the child node exists and false * otherwise. * - * @param name The qualified name of the child node. + * @param name The name of the child node. * @return true if the child node exists; false otherwise. * @throws RepositoryException If an unspecified error occurs. */ @@ -1455,7 +1555,7 @@ * Returns true if the child node exists and false * 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 true if the child node exists; false otherwise. * @throws RepositoryException If an unspecified error occurs. @@ -1479,7 +1579,7 @@ * Returns the property of this node with the specified * name. * - * @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 name. * @throws ItemNotFoundException If no property exists with the * specified name. @@ -1503,7 +1603,7 @@ * Returns true if the property exists and false * otherwise. * - * @param name The qualified name of the property. + * @param name The name of the property. * @return true if the property exists; false 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 list = new ArrayList(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 cneList = new ArrayList(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 mixinNames = data.getNodeState().getMixinTypeNames(); if (mixinNames.isEmpty()) { return new NodeType[0]; } NodeType[] nta = new NodeType[mixinNames.size()]; - Iterator iter = mixinNames.iterator(); + Iterator 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 mixins = new HashSet(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 list = new ArrayList(); 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 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 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 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 internalGetMergeFailed() throws RepositoryException { + HashSet set = new HashSet(); 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 set) throws RepositoryException { if (set.isEmpty()) { internalSetProperty(NameConstants.JCR_MERGEFAILED, (InternalValue[]) null); } else { InternalValue[] vals = new InternalValue[set.size()]; - Iterator iter = set.iterator(); + Iterator 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 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 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 restored = new HashSet(); 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 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(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 propNames = new HashSet(); + 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 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 filteredList = new ArrayList(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 props = new ArrayList(); + 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 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(); - for (NodeIterator nit = result.getNodes(); nit.hasNext(); ) { + ArrayList l = new ArrayList(); + 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 oldDefs = new HashSet(Arrays.asList(entOld.getAllItemDefs())); + Set newDefs = new HashSet(Arrays.asList(entNew.getAllItemDefs())); + Set allDefs = new HashSet(Arrays.asList(entAll.getAllItemDefs())); // added child item definitions - Set addedDefs = new HashSet(newDefs); + Set addedDefs = new HashSet(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 set = new HashSet(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 list = new ArrayList(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 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 Name of the property. * - * @return qualified name + * @return Name of the property. */ public Name getName() { return propName;