Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 76611 invoked from network); 9 Nov 2006 09:09:55 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 9 Nov 2006 09:09:55 -0000 Received: (qmail 66126 invoked by uid 500); 9 Nov 2006 09:10:06 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 66042 invoked by uid 500); 9 Nov 2006 09:10:06 -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 66033 invoked by uid 99); 9 Nov 2006 09:10:06 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 09 Nov 2006 01:10:06 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 09 Nov 2006 01:09:53 -0800 Received: by eris.apache.org (Postfix, from userid 65534) id 92A2B1A9846; Thu, 9 Nov 2006 01:09:25 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r472818 - /jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ Date: Thu, 09 Nov 2006 09:09:25 -0000 To: commits@jackrabbit.apache.org From: angela@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20061109090925.92A2B1A9846@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: angela Date: Thu Nov 9 01:09:24 2006 New Revision: 472818 URL: http://svn.apache.org/viewvc?view=rev&rev=472818 Log: work in progress. - nodestates must always be connected to their cne upon creation TODO: add some sort of caching to avoid traffic overhead - add TODO for refresh, that currently doesn't work properly - ItemState.refresh only takes changelog and returns the ids of the processed states. cleanup of events is left to caller. - move of NodeStates does not work - PathResolver: force start to be an NodeState - all MODIFIED status for SessionStates as well in order to make sure that listeners are informed about external changes even if the state is EXISTING. next TODO: make sure, that public getChildNodeEntry/ies and hasChildNodeEntry check for validity of the connected NodeState. don't return entries, where the nodestate is (transiently) removed or stale. Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeEntries.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateCache.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java Thu Nov 9 01:09:24 2006 @@ -188,34 +188,39 @@ * present in the cache. */ protected ItemState lookup(ItemId id) { - ItemState state; + NodeState start; // resolve UUID if (id.getUUID() != null) { - state = cache.getNodeState(id.getUUID()); - if (state == null) { + start = cache.getNodeState(id.getUUID()); + if (start == null) { // not cached return null; } } else { // start from root try { - state = getRootState(); + start = getRootState(); } catch (ItemStateException e) { - log.warn("unable to get root node state:" + e.getMessage()); + // should never occur + log.error("Error while retrieving root node state:" + e.getMessage()); return null; } } - // resolve relative path - if (id.getPath() != null) { + if (id.getPath() == null) { + // path is null -> id points to a state identified by uuid + return start; + } else { + // resolve path part try { - state = PathResolver.lookup(state, id.getPath()); + return PathResolver.lookup(start, id.getPath()); + } catch (NoSuchItemStateException e) { + log.debug("exception while looking up state with id: " + id); + return null; } catch (ItemStateException e) { - log.warn("exception while looking up state with id: " + id); + log.debug("exception while looking up state with id: " + id); return null; } } - - return state; } } Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeEntries.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeEntries.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeEntries.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeEntries.java Thu Nov 9 01:09:24 2006 @@ -112,14 +112,15 @@ /** * Returns the ChildNodeEntry for the given - * nodeState. + * nodeState. Note, that this method does not check if the + * given childNodeEntry (and its attached NodeState) is still valid. * - * @param nodeState the node state. + * @param childState the child node state for which a entry is searched. * @return the ChildNodeEntry or null if there - * is no ChildNodeEntry for nodeState. + * is no ChildNodeEntry for the given NodeState. */ - ChildNodeEntry get(NodeState nodeState) { - Object o = nameMap.get(nodeState.getQName()); + ChildNodeEntry get(NodeState childState) { + Object o = nameMap.get(childState.getQName()); if (o == null) { // no matching child node entry return null; @@ -131,7 +132,7 @@ ChildNodeEntry cne = n.getChildNodeEntry(); // only check available child node entries try { - if (cne.isAvailable() && cne.getNodeState() == nodeState) { + if (cne.isAvailable() && cne.getNodeState() == childState) { return cne; } } catch (ItemStateException e) { @@ -142,7 +143,7 @@ // single child node with this name ChildNodeEntry cne = ((LinkedEntries.LinkNode) o).getChildNodeEntry(); try { - if (cne.isAvailable() && cne.getNodeState() == nodeState) { + if (cne.isAvailable() && cne.getNodeState() == childState) { return cne; } } catch (ItemStateException e) { @@ -241,7 +242,7 @@ } } else { // then this child node entry has never been accessed - // before and is assumed valid + // before and is assumed valid // TODO: check if correct. index--; } if (index == 0) { @@ -268,9 +269,9 @@ if (uuid == null) { throw new IllegalArgumentException(); } - List l = get(nodeName); - for (Iterator it = l.iterator(); it.hasNext();) { - ChildNodeEntry cne = (ChildNodeEntry) it.next(); + Iterator cneIter = (nodeName != null) ? get(nodeName).iterator() : iterator(); + while (cneIter.hasNext()) { + ChildNodeEntry cne = (ChildNodeEntry) cneIter.next(); if (uuid.equals(cne.getUUID())) { return cne; } @@ -309,9 +310,9 @@ * Adds a ChildNodeEntry for a child node with the given * name and an optional uuid. * - * @param nodeName the name of the child node. - * @param uuid the UUID of the child node if it can be identified - * with a UUID; otherwise null. + * @param nodeName The name of the child node. + * @param uuid The UUID of the child node if it can be identified with a UUID; + * otherwise null. * @return the created ChildNodeEntry. */ private ChildNodeEntry add(QName nodeName, String uuid) { @@ -455,8 +456,7 @@ * beforeNode does not have a ChildNodeEntry * in this ChildNodeEntries. */ - void reorder(NodeState insertNode, NodeState beforeNode) - throws NoSuchItemStateException { + void reorder(NodeState insertNode, NodeState beforeNode) throws NoSuchItemStateException { Object insertObj = nameMap.get(insertNode.getQName()); // the link node to move LinkedEntries.LinkNode insertLN = getLinkNode(insertNode); @@ -510,19 +510,23 @@ ChildNodeEntry newCne = ChildNodeReference.create(childState, nodeState.isf, nodeState.idFactory); entries.replaceNode(ln, newCne); } catch (NoSuchItemStateException e) { - log.error("Internal error.", e); + // should never occur. + log.error("Internal Error: ", e); } } /** * Returns the matching LinkNode from a list or a single - * LinkNode. + * LinkNode. Note, that in contrast to {@link #getLinkNode(ChildNodeEntry)} + * this method will throw NoSuchItemStateException if none of the + * entries matches either due to missing entry for given state name or due + * to missing availability of the ChildNodeEntry. * - * @param nodeState the NodeState which is the value - * of on of the LinkNodes. + * @param nodeState the NodeState that is compared to the + * resolution of any ChildNodeEntry that matches by name. * @return the matching LinkNode. * @throws NoSuchItemStateException if none of the LinkNodes - * matches. + * matches. */ private LinkedEntries.LinkNode getLinkNode(NodeState nodeState) throws NoSuchItemStateException { @@ -531,7 +535,7 @@ // no matching child node entry throw new NoSuchItemStateException(nodeState.getQName().toString()); } - + if (listOrLinkNode instanceof List) { // has same name sibling for (Iterator it = ((List) listOrLinkNode).iterator(); it.hasNext();) { @@ -560,8 +564,10 @@ throw new NoSuchItemStateException(nodeState.getQName().toString()); } - //---------------------------------------< unmodifiable Collection view >--- - + //--------------------------------------------< unmodifiable Collection >--- + /** + * @see Collection#contains(Object) + */ public boolean contains(Object o) { if (o instanceof ChildNodeEntry) { // narrow down to same name sibling nodes and check list @@ -571,6 +577,9 @@ } } + /** + * @see Collection#containsAll(Collection) + */ public boolean containsAll(Collection c) { Iterator iter = c.iterator(); while (iter.hasNext()) { @@ -581,23 +590,38 @@ return true; } + /** + * @see Collection#isEmpty() + */ public boolean isEmpty() { return entries.isEmpty(); } + /** + * @see Collection#iterator() + */ public Iterator iterator() { return UnmodifiableIterator.decorate(entries.iterator()); } + /** + * @see Collection#size() + */ public int size() { return entries.size(); } + /** + * @see Collection#toArray() + */ public Object[] toArray() { ChildNodeEntry[] array = new ChildNodeEntry[size()]; return toArray(array); } + /** + * @see Collection#toArray(Object[]) + */ public Object[] toArray(Object[] a) { if (!a.getClass().getComponentType().isAssignableFrom(ChildNodeEntry.class)) { throw new ArrayStoreException(); @@ -616,31 +640,61 @@ return a; } + /** + * Throws UnsupportedOperationException. + * + * @see Collection#add(Object) + */ public boolean add(Object o) { throw new UnsupportedOperationException(); } + /** + * Throws UnsupportedOperationException. + * + * @see Collection#addAll(Collection) + */ public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } + /** + * Throws UnsupportedOperationException. + * + * @see Collection#clear() + */ public void clear() { throw new UnsupportedOperationException(); } + /** + * Throws UnsupportedOperationException. + * + * @see Collection#remove(Object) + */ public boolean remove(Object o) { throw new UnsupportedOperationException(); } + /** + * Throws UnsupportedOperationException. + * + * @see Collection#removeAll(Collection) + */ public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } + /** + * Throws UnsupportedOperationException. + * + * @see Collection#retainAll(Collection) + */ public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } - + //-------------------------------------------------< AbstractLinkedList >--- /** * An implementation of a linked list which provides access to the internal * LinkNode which links the entries of the list. @@ -698,6 +752,7 @@ * * @param value a child node entry. * @return a wrapping {@link LinkedEntries.LinkNode}. + * @see AbstractLinkedList#createNode(Object) */ protected Node createNode(Object value) { return new LinkNode(value); @@ -705,6 +760,7 @@ /** * @return a new LinkNode. + * @see AbstractLinkedList#createHeaderNode() */ protected Node createHeaderNode() { return new LinkNode(); @@ -746,7 +802,7 @@ }; } - //----------------------------------------------------------------------- + //---------------------------------------------------------------------- /** * Extends the AbstractLinkedList.Node. Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java Thu Nov 9 01:09:24 2006 @@ -341,6 +341,7 @@ synchronized (this) { reset(); } + setStatus(Status.MODIFIED); } else if (status == Status.EXISTING_MODIFIED) { setStatus(Status.STALE_MODIFIED); } @@ -445,11 +446,12 @@ * Used on the target state of a save call AFTER the changelog has been * successfully submitted to the SPI.. * - * @param events * @param changeLog + * @return a Set of ItemIds in order to allow the caller to + * remove those events that have already been processed. * @throws IllegalStateException if this state is a 'session' state. */ - abstract void refresh(Collection events, ChangeLog changeLog) throws IllegalStateException; + abstract Set refresh(ChangeLog changeLog) throws IllegalStateException; /** * Copy all state information from overlayed state to this state @@ -527,21 +529,6 @@ default: String msg = "Cannot mark item state with status " + status + " modified."; throw new IllegalStateException(msg); - } - } - - //-------------------------------------------------------------------------- - /** - * - * @param events - * @param processedState - */ - static void removeEvent(Collection events, ItemState processedState) { - for (Iterator it = events.iterator(); it.hasNext();) { - if (((Event)it.next()).getItemId().equals(processedState.getId())) { - it.remove(); - break; - } } } } Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateCache.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateCache.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateCache.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateCache.java Thu Nov 9 01:09:24 2006 @@ -87,10 +87,12 @@ private void putToCache(ItemState state) { if (state.isNode() && (state.getStatus() == Status.EXISTING || state.getStatus() == Status.MODIFIED)) { NodeState nodeState = (NodeState) state; + // NOTE: uuid is retrieved from the state and not from the NodeId. String uuid = nodeState.getUUID(); if (uuid != null) { uuid2NodeState.put(uuid, nodeState); } } + // TODO: add caching for other items as well } } Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java Thu Nov 9 01:09:24 2006 @@ -123,7 +123,6 @@ this.uuid = uuid; this.nodeTypeName = nodeTypeName; this.definition = definition; - assertAvailability(); } /** @@ -151,7 +150,6 @@ init(wspState.getMixinTypeNames(), wspState.getChildNodeEntries(), wspState.getPropertyNames(), wspState.getNodeReferences()); } } - assertAvailability(); } /** @@ -185,17 +183,6 @@ this.references = references; } - private void assertAvailability() { - // TODO: TOBEFIXED. duality of creating states via ISM or via factory may result in a cached state, that is not connected to its cne. - if (uuid != null && parent != null) { - // make sure this state is connected to its childNode-entry - ChildNodeEntry cne = parent.childNodeEntries.get(name, uuid); - if (cne != null && !cne.isAvailable()) { - parent.childNodeEntries.replaceEntry(this); - } - } - } - //----------------------------------------------------------< ItemState >--- /** * Determines if this item state represents a node. @@ -360,17 +347,17 @@ } /** - * Determines if there are any child node entries. + * Determines if there are any valid child node entries. * * @return true if there are child node entries, - * false otherwise. + * false otherwise. */ public boolean hasChildNodeEntries() { return containsValidChildNodeEntry(childNodeEntries); } /** - * Determines if there is a ChildNodeEntry with the + * Determines if there is a valid ChildNodeEntry with the * specified name. * * @param name QName object specifying a node name @@ -388,7 +375,7 @@ * @param name QName object specifying a node name * @param index 1-based index if there are same-name child node entries * @return true if there is a ChildNodeEntry with - * the specified name and index. + * the specified name and index. */ public synchronized boolean hasChildNodeEntry(QName name, int index) { return childNodeEntries.get(name, index) != null; @@ -409,13 +396,34 @@ /** * Returns the ChildNodeEntry with the specified + * NodeId or null if there's no matching + * entry. + * + * @param nodeId the id of the child node state. + * @return the ChildNodeEntry with the specified + * NodeId or null if there's no matching entry. + */ + public synchronized ChildNodeEntry getChildNodeEntry(NodeId nodeId) { + String uuid = nodeId.getUUID(); + Path path = nodeId.getPath(); + if (uuid != null && path == null) { + // retrieve child-entry by uuid + return childNodeEntries.get(null, uuid); + } else { + // retrieve child-entry by name and index + Path.PathElement nameElement = path.getNameElement(); + return childNodeEntries.get(nameElement.getName(), nameElement.getIndex()); + } + } + + /** + * Returns the ChildNodeEntry with the specified * NodeState or null if there's no matching * entry. * * @param nodeState the child node state. * @return the ChildNodeEntry with the specified - * NodeState or null if there's no - * matching entry. + * NodeState or null if there's no matching entry. */ private synchronized ChildNodeEntry getChildNodeEntry(NodeState nodeState) { return childNodeEntries.get(nodeState); @@ -465,7 +473,7 @@ return false; } } else { - // then it must be valid + // then it must be valid // TODO check if this assumption is correct. return true; } } @@ -525,39 +533,26 @@ /* * Returns the property state with the given name. * - * @param propertyName the name of the property state to return. - * @throws NoSuchItemStateException if there is no property state with the - * given name. - * @throws ItemStateException if an error occurs while retrieving the - * property state. + * @param propertyName The name of the property state to return. + * @throws NoSuchItemStateException If there is no (valid) property state + * with the given name. + * @throws ItemStateException If an error occurs while retrieving the + * property state. */ public synchronized PropertyState getPropertyState(QName propertyName) - throws NoSuchItemStateException, ItemStateException { - PropertyState propState = getAnyPropertyState(propertyName); - if (propState.isValid()) { - return propState; - } else { - throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString()); - } - } + throws NoSuchItemStateException, ItemStateException { - /** - * Returns the property state with the given name and also takes removed - * property states into account. - * - * @param propertyName the name of the property state to return. - * @throws NoSuchItemStateException if there is no property state with the - * given name. - * @throws ItemStateException if an error occurs while retrieving the - * property state. - */ - public synchronized PropertyState getAnyPropertyState(QName propertyName) - throws NoSuchItemStateException, ItemStateException { ChildPropertyEntry propEntry = (ChildPropertyEntry) properties.get(propertyName); if (propEntry == null) { throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString()); + } else { + PropertyState propState = propEntry.getPropertyState(); + if (propState.isValid()) { + return propState; + } else { + throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString()); + } } - return propEntry.getPropertyState(); } /** @@ -606,8 +601,8 @@ * name. * * @param cne the ChildNodeEntry instance. - * @return the index of the child node entry or 0 if it is not - * found in this NodeState. + * @return the index of the child node entry or Path.INDEX_UNDEFINED + * if it is not found in this NodeState. */ public int getChildNodeIndex(ChildNodeEntry cne) { List sns = childNodeEntries.get(cne.getName()); @@ -630,6 +625,7 @@ } } else { // cne has not been resolved yet -> increase counter. + // TODO: check if assuption is correct index++; } } @@ -715,13 +711,14 @@ //----------------------------------------------------< Session - State >--- /** * {@inheritDoc} - * @see ItemState#refresh(Collection,ChangeLog) + * @see ItemState#refresh(ChangeLog) */ - void refresh(Collection events, ChangeLog changeLog) throws IllegalStateException { + Set refresh(ChangeLog changeLog) throws IllegalStateException { // remember parent states that have need to adjust their uuid/mixintypes // or that got a new child entry added or existing entries removed. - HashMap modParents = new HashMap(); + Map modParents = new HashMap(); + Set processedIds = new HashSet(); // process deleted states from the changelog for (Iterator it = changeLog.deletedStates(); it.hasNext();) { @@ -742,7 +739,7 @@ } // don't remove processed state from changelog, but from event list // state on changelog is used for check if parent is deleted as well. - removeEvent(events, state); + processedIds.add(state.getId()); } // process added states from the changelog. since the changlog maintains @@ -790,7 +787,7 @@ } it.remove(); - removeEvent(events, addedState); + processedIds.add(addedState.getId()); } catch (ItemStateException e) { log.error("Internal error.", e); } @@ -799,27 +796,50 @@ for (Iterator it = changeLog.modifiedStates(); it.hasNext();) { ItemState modState = (ItemState) it.next(); if (modState.isNode()) { - continue; + NodeState modNodeState = (NodeState) modState; + // handle moved nodes + if (isMovedState(modNodeState)) { + // move overlayed state as well + NodeState newParent = (NodeState) modState.parent.overlayedState; + NodeState overlayed = (NodeState) modState.overlayedState; + ItemId removedId = overlayed.getId(); + try { + overlayed.parent.moveEntry(newParent, overlayed, modNodeState.getQName(), modNodeState.getDefinition()); + } catch (RepositoryException e) { + // should never occur + log.error("Internal error while moving childnode entries.", e); + } + // and mark the moved state existing + modNodeState.setStatus(Status.EXISTING); + it.remove(); + + processedIds.add(removedId); + processedIds.add(modNodeState.getId()); + } else { + modifiedParent((NodeState)modState, null, modParents); + } + } else { + // push changes down to overlayed state + int type = ((PropertyState) modState).getType(); + QValue[] values = ((PropertyState) modState).getValues(); + ((PropertyState) modState.overlayedState).init(type, values); + + modState.setStatus(Status.EXISTING); + // if property state defines a modified jcr:mixinTypes + // the parent is listed as modified state and needs to be + // processed at the end. + if (isUuidOrMixin(modState.getQName())) { + modifiedParent(modState.getParent(), modState, modParents); + } + it.remove(); + // remove the property-modification event from the set + processedIds.add(modState.getId()); } - // push changes down to overlayed state - int type = ((PropertyState) modState).getType(); - QValue[] values = ((PropertyState) modState).getValues(); - ((PropertyState) modState.overlayedState).init(type, values); - - modState.setStatus(Status.EXISTING); - // if property state defines a modified jcr:mixinTypes - // the parent is listed as modified state and needs to be - // processed at the end. - if (isUuidOrMixin(modState.getQName())) { - modifiedParent(this, modState, modParents); - } - // remove the processed event from the set - it.remove(); - removeEvent(events, modState); } - /* process all parent states that need their uuid or mixin-types being - adjusted because that property has been added or modified */ + /* process all parent states that are marked modified and eventually + need their uuid or mixin-types being adjusted because that property + has been added, modified or removed */ for (Iterator it = modParents.keySet().iterator(); it.hasNext();) { NodeState parent = (NodeState) it.next(); List l = (List) modParents.get(parent); @@ -838,6 +858,8 @@ // TODO: discard state and force reload of all data } } + + return processedIds; } /** @@ -957,6 +979,7 @@ * @see ItemState#revert(Set) */ void revert(Set affectedItemStates) { + // TODO: TOBEFIXED. revert must include an update with the latest state present on the server checkIsSessionState(); // copy to new list, when a property is reverted it may call this node @@ -1215,9 +1238,17 @@ throws RepositoryException { checkIsSessionState(); + moveEntry(newParent, childState, newName, newDefinition); + // mark both this and newParent modified + markModified(); + childState.markModified(); + newParent.markModified(); + } + + private void moveEntry(NodeState newParent, NodeState childState, QName newName, QNodeDefinition newDefinition) throws RepositoryException { ChildNodeEntry oldEntry = childNodeEntries.remove(childState); if (oldEntry != null) { - childState.rename(newName); + childState.name = newName; // re-parent target node childState.parent = newParent; // set definition according to new definition required by the new parent @@ -1225,26 +1256,8 @@ // add child node entry to new parent newParent.childNodeEntries.add(childState); } else { - throw new RepositoryException("Unexpected error: Child state to be renamed does not exist."); + throw new RepositoryException("Unexpected error: Child state to be moved does not exist."); } - // mark both this and newParent modified - markModified(); - childState.markModified(); - newParent.markModified(); - } - - /** - * Renames this node to newName. - * - * @param newName the new name for this node state. - * @throws IllegalStateException if this is the root node. - */ - private synchronized void rename(QName newName) { - checkIsSessionState(); - if (getParent() == null) { - throw new IllegalStateException("root node cannot be renamed"); - } - name = newName; } //---------------------------------------------------------< diff methods > @@ -1369,6 +1382,7 @@ } } else { // then it has never been accessed and must exist + // TODO: check if this assumption is correct return true; } } @@ -1449,5 +1463,8 @@ log.warn("Error while adjusting nodestate: Overlayed state is missing."); } } - //------------------------------------------------------< inner classes >--- + + private static boolean isMovedState(NodeState modState) { + return modState.overlayedState.parent != modState.parent.overlayedState; + } } Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java Thu Nov 9 01:09:24 2006 @@ -28,7 +28,7 @@ /** * The starting point to resolve the path. */ - private final ItemState start; + private final NodeState start; /** * The path to resolve. @@ -43,7 +43,7 @@ * @throws IllegalArgumentException if not normalized or starts with a * parent ('..') path element. */ - private PathResolver(ItemState start, Path relPath) { + private PathResolver(NodeState start, Path relPath) { if (!relPath.isNormalized() || relPath.getElement(0).denotesParent()) { throw new IllegalArgumentException("path must be relative and must " + "not contain parent path elements"); @@ -66,7 +66,7 @@ * or starts with a parent ('..') path * element. */ - public static ItemState resolve(ItemState start, Path path) + public static ItemState resolve(NodeState start, Path path) throws NoSuchItemStateException, ItemStateException { return new PathResolver(start, path).resolve(); } @@ -87,7 +87,7 @@ * or starts with a parent ('..') path * element. */ - public static ItemState lookup(ItemState start, Path path) + public static ItemState lookup(NodeState start, Path path) throws NoSuchItemStateException, ItemStateException { return new PathResolver(start, path).lookup(); } @@ -97,15 +97,11 @@ * * @return the resolved item state. * @throws NoSuchItemStateException the the item state does not exist. - * @throws ItemStateException if an error occurs while retrieving the - * item state. + * @throws ItemStateException if an error occurs while retrieving the item state. */ private ItemState resolve() throws NoSuchItemStateException, ItemStateException { - if (!start.isNode()) { - throw new NoSuchItemStateException(path.toString()); - } - NodeState state = (NodeState) start; + NodeState state = start; for (int i = 0; i < path.getLength(); i++) { Path.PathElement elem = path.getElement(i); // check for root element @@ -119,8 +115,8 @@ // first try to resolve node if (state.hasChildNodeEntry(elem.getName(), elem.getNormalizedIndex())) { - state = state.getChildNodeEntry(elem.getName(), - elem.getNormalizedIndex()).getNodeState(); + ChildNodeEntry cne = state.getChildNodeEntry(elem.getName(), elem.getNormalizedIndex()); + state = cne.getNodeState(); } else if (elem.getIndex() == 0 // property must not have index && state.hasPropertyName(elem.getName()) && i == path.getLength() - 1) { // property must be final path element @@ -133,21 +129,18 @@ } /** - * Resolves the path but does not the ItemState if it is not - * yet loaded. + * Resolves the path but does not return the ItemState if it + * has not yet been loaded. * * @return the resolved item state or null if the item is not - * available. + * available. * @throws NoSuchItemStateException the the item state does not exist. - * @throws ItemStateException if an error occurs while retrieving the - * item state. + * @throws ItemStateException if an error occurs while retrieving the + * item state. */ private ItemState lookup() throws NoSuchItemStateException, ItemStateException { - if (!start.isNode()) { - throw new NoSuchItemStateException(path.toString()); - } - NodeState state = (NodeState) start; + NodeState state = start; for (int i = 0; i < path.getLength(); i++) { Path.PathElement elem = path.getElement(i); // first try to resolve node Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java Thu Nov 9 01:09:24 2006 @@ -35,6 +35,7 @@ import java.util.Set; import java.util.Collection; import java.util.Iterator; +import java.util.HashSet; /** * PropertyState represents the state of a Property. @@ -259,9 +260,10 @@ //----------------------------------------------------< Session - State >--- /** * {@inheritDoc} - * @see ItemState#refresh(Collection,ChangeLog) + * @see ItemState#refresh(ChangeLog) */ - void refresh(Collection events, ChangeLog changeLog) throws IllegalStateException { + Set refresh(ChangeLog changeLog) throws IllegalStateException { + Set processedIds = new HashSet(1); for (Iterator it = changeLog.modifiedStates(); it.hasNext();) { ItemState modState = (ItemState) it.next(); if (modState == this) { @@ -275,9 +277,10 @@ setStatus(Status.EXISTING); // parent must not be informed, since all properties that // affect the parent state (uuid, mixins) are protected. - removeEvent(events, modState); + processedIds.add(modState.getId()); } } + return processedIds; } /** @@ -313,6 +316,7 @@ * @see ItemState#revert(Set) */ void revert(Set affectedItemStates) { + // TODO: TOBEFIXED. revert must include an update with the latest state present on the server checkIsSessionState(); switch (getStatus()) { Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java Thu Nov 9 01:09:24 2006 @@ -124,6 +124,7 @@ case EXISTING_MODIFIED: /* save, revert */ case EXISTING_REMOVED: /* revert */ case STALE_MODIFIED: /* revert */ + case MODIFIED: isValid = true; break; /* REMOVED, STALE_DESTROYED -> false */ @@ -142,9 +143,11 @@ case REMOVED: isValid = (oldStatus == NEW || oldStatus == EXISTING || oldStatus == EXISTING_REMOVED); break; - /* default: - NEW cannot change state to NEW -> false - MODIFIED never applicable to session state -> false */ + case MODIFIED: + isValid = (oldStatus == EXISTING); + break; + /* default: + NEW cannot change state to NEW -> false */ } } return isValid; Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java Thu Nov 9 01:09:24 2006 @@ -24,6 +24,7 @@ import org.apache.jackrabbit.spi.NodeId; import org.apache.jackrabbit.spi.PropertyId; import org.apache.jackrabbit.name.QName; +import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry; /** * TransientISFactory... @@ -33,14 +34,14 @@ private static Logger log = LoggerFactory.getLogger(TransientISFactory.class); private final IdFactory idFactory; - private final ItemStateManager parent; + private final ItemStateManager workspaceItemStateMgr; private ItemStateCache cache; private ItemStateCreationListener listener; - TransientISFactory(IdFactory idFactory, ItemStateManager parent) { + TransientISFactory(IdFactory idFactory, ItemStateManager workspaceItemStateMgr) { this.idFactory = idFactory; - this.parent = parent; + this.workspaceItemStateMgr = workspaceItemStateMgr; } //------------------------------------------< TransientItemStateFactory >--- @@ -99,7 +100,7 @@ */ public NodeState createRootState(ItemStateManager ism) throws ItemStateException { // retrieve state to overlay - NodeState overlayedState = (NodeState) parent.getRootState(); + NodeState overlayedState = (NodeState) workspaceItemStateMgr.getRootState(); NodeState nodeState = new NodeState(overlayedState, null, Status.EXISTING, this, idFactory); nodeState.addListener(cache); @@ -117,17 +118,27 @@ NodeState nodeState = cache.getNodeState(nodeId); if (nodeState == null) { // retrieve state to overlay - NodeState overlayedState = (NodeState) parent.getItemState(nodeId); + NodeState overlayedState = (NodeState) workspaceItemStateMgr.getItemState(nodeId); NodeState overlayedParent = overlayedState.getParent(); - NodeState parentState = null; - if (overlayedParent != null) { + if (overlayedParent == null) { + // special case root state + return createRootState(ism); + } + + NodeState parentState = (NodeState) overlayedParent.getSessionState(); + if (parentState == null) { parentState = (NodeState) ism.getItemState(overlayedParent.getId()); } - nodeState = new NodeState(overlayedState, parentState, Status.EXISTING, this, idFactory); - nodeState.addListener(cache); - cache.created(nodeState); + ChildNodeEntry cne = parentState.getChildNodeEntry(nodeId); + if (cne != null) { + nodeState = cne.getNodeState(); + nodeState.addListener(cache); + cache.created(nodeState); + } else { + throw new NoSuchItemStateException("No such item " + nodeId.toString()); + } } return nodeState; } @@ -142,7 +153,7 @@ NodeState nodeState = cache.getNodeState(nodeId); if (nodeState == null) { // retrieve state to overlay - NodeState overlayedState = (NodeState) parent.getItemState(nodeId); + NodeState overlayedState = (NodeState) workspaceItemStateMgr.getItemState(nodeId); nodeState = new NodeState(overlayedState, parentState, Status.EXISTING, this, idFactory); nodeState.addListener(cache); @@ -162,7 +173,7 @@ PropertyState propState = cache.getPropertyState(propertyId); if (propState == null) { // retrieve state to overlay - PropertyState overlayedState = (PropertyState) parent.getItemState(propertyId); + PropertyState overlayedState = (PropertyState) workspaceItemStateMgr.getItemState(propertyId); propState = new PropertyState(overlayedState, parentState, Status.EXISTING, this, idFactory); propState.addListener(cache); Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Thu Nov 9 01:09:24 2006 @@ -309,6 +309,10 @@ break; case Status.STALE_MODIFIED: // state is now stale. keep in modified. wait until refreshed + case Status.MODIFIED: + // MODIFIED is only possible on EXISTING states -> thus, there + // must not be any transient modifications for that state. + // we ignore it. break; default: log.error("ItemState has invalid status: " + state.getStatus()); Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java Thu Nov 9 01:09:24 2006 @@ -73,7 +73,8 @@ */ public NodeState createRootState(ItemStateManager ism) throws ItemStateException { try { - return createNodeState(service.getRootId(sessionInfo), ism); + NodeInfo info = service.getNodeInfo(sessionInfo, service.getRootId(sessionInfo)); + return createNodeState(info, null); } catch (RepositoryException e) { throw new ItemStateException("Internal error while building root state."); } @@ -90,15 +91,13 @@ throws NoSuchItemStateException, ItemStateException { try { NodeInfo info = service.getNodeInfo(sessionInfo, nodeId); - - // get parent - NodeId parentId = (info.getParentId() != null) ? info.getParentId() : null; - NodeState parent = (parentId != null) ? (NodeState) ism.getItemState(parentId) : null; - - if (parent != null) { - return parent.getChildNodeEntry(info.getQName(), info.getIndex()).getNodeState(); + NodeId parentId = info.getParentId(); + if (parentId != null) { + NodeState parent = (NodeState) ism.getItemState(parentId); + return parent.getChildNodeEntry(nodeId).getNodeState(); } else { - return createNodeState(info, parent); + // special case for root state + return createNodeState(info, null); } } catch (ItemNotFoundException e) { throw new NoSuchItemStateException(e.getMessage(), e); @@ -129,8 +128,8 @@ /** * Creates the node with information retrieved from info. * - * @param info the NodeInfo to use to create the - * NodeState. + * @param info the NodeInfo to use to create the + * NodeState. * @param parent the parent NodeState. * @return the new NodeState. */ Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java?view=diff&rev=472818&r1=472817&r2=472818 ============================================================================== --- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java (original) +++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java Thu Nov 9 01:09:24 2006 @@ -21,6 +21,7 @@ import org.apache.jackrabbit.spi.Event; import org.apache.jackrabbit.spi.EventBundle; import org.apache.jackrabbit.spi.EventIterator; +import org.apache.jackrabbit.spi.ItemId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,7 +74,14 @@ // that have been persisted now: NEW-states will be connected to their // overlayed state, EXISTING_REMOVED states will be definitely removed, // EXISTING_MODIFIED states are merged with their workspace-state. - changeLog.getTarget().refresh(evs, changeLog); + Set processedIds = changeLog.getTarget().refresh(changeLog); + for (Iterator it = evs.iterator(); it.hasNext();) { + ItemId evId = ((Event)it.next()).getItemId(); + if (processedIds.contains(evId)) { + it.remove(); + } + } + // all events not covered by the changelog must not be handled on the // session-states -> treat the same way as events returned by // workspace operations.