All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.modeshape.jcr.cache.document.SessionChildReferences Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.modeshape.jcr.cache.document;

import java.util.Iterator;
import org.modeshape.common.annotation.ThreadSafe;
import org.modeshape.jcr.cache.ChildReference;
import org.modeshape.jcr.cache.ChildReferences;
import org.modeshape.jcr.cache.NodeKey;
import org.modeshape.jcr.value.Name;

/**
 * A {@link ChildReferences} implementation that projects a single, changeable view of the child references of a node, allowing
 * child references to be added to the end of the persisted state. This view always reflects the view's changes on top of the
 * current persisted list of child references, even when the persisted state is changed by other sessions.
 * 

* For example, consider a node A that has two children, B and C. If a {@link SessionChildReferences} instance is created for A, * then it includes {@link ChildReference} for nodes B and C. If a new child node, D, is created and appended to the list, the * MutableChildReferences object will show three children: B, C and D. Before these changes are saved, however, another client * adds to node A a new node, E, and persists those changes. At that instant, the MutableChildReferences will see four children * for node A: the persisted children B, C and E, plus the transient node D that has not yet been saved. *

*/ @ThreadSafe public class SessionChildReferences extends AbstractChildReferences { private final ChildReferences persisted; private final MutableChildReferences appended; private final SessionNode.ChangedChildren changedChildren; public SessionChildReferences( ChildReferences persisted, MutableChildReferences appended, SessionNode.ChangedChildren changedChildren ) { this.persisted = persisted != null ? persisted : ImmutableChildReferences.EMPTY_CHILD_REFERENCES; this.appended = appended; this.changedChildren = changedChildren; } @Override public long size() { return persisted.size() + (appended != null ? appended.size() : 0); } @Override public int getChildCount( Name name ) { int appendedChildren = appended != null ? appended.getChildCount(name) : 0; int persistedChildrenCount = 0; int removedChildren = 0; int renamedChildren = 0; int appendedThenReorderedChildren = 0; for (Iterator childReferenceIterator = persisted.iterator(name); childReferenceIterator.hasNext(); ) { ChildReference persistedChild = childReferenceIterator.next(); ++persistedChildrenCount; if (changedChildren != null) { if (changedChildren.isRemoved(persistedChild)) { --removedChildren; continue; } if (changedChildren.isRenamed(persistedChild)) { --renamedChildren; } } } if (changedChildren != null) { appendedThenReorderedChildren = changedChildren.insertionCount(name); if (changedChildren.isRenamed(name)) { ++renamedChildren; } } return persistedChildrenCount + appendedChildren + appendedThenReorderedChildren + removedChildren + renamedChildren; } @Override public ChildReference getChild( Name name, int snsIndex, Context context ) { if (changedChildren != null) context = new WithChanges(context, changedChildren); // First look in the delegate references ... ChildReference ref = persisted.getChild(name, snsIndex, context); if (ref == null) { if (appended != null) { // Look in the added ... ref = appended.getChild(name, snsIndex, context); if (ref == null && changedChildren != null && changedChildren.insertionCount() > 0) { //look in added and then reordered (which don't appear as appended) Iterator insertionsWithName = changedChildren.insertions(name); while (insertionsWithName.hasNext()) { for (ChildReference inserted : insertionsWithName.next().inserted()) { if (inserted.getSnsIndex() == snsIndex) { return inserted; } } } } } } return ref; } @Override public boolean hasChild( NodeKey key ) { return getChild(key, new BasicContext()) != null; } @Override public ChildReference getChild( NodeKey key ) { return getChild(key, new BasicContext()); } @Override public ChildReference getChild( NodeKey key, Context context ) { if (changedChildren != null) context = new WithChanges(context, changedChildren); // First look in the delegate references ... // Note that we don't know the name of the child yet, so we'll have to come back // to the persisted node after we know the name ... ChildReference ref = persisted.getChild(key, context); if (ref == null) { if (appended != null) { // Look in the added ... ref = appended.getChild(key, context); if (ref != null) { // The node was appended, but we need to increment the SNS indexes // by the number of same-named children in 'persisted' ... int numSnsInPersisted = persisted.getChildCount(ref.getName()); if (numSnsInPersisted != 0) { // There were some persisted with the same name, and we didn't find these // when looking in the persisted node above. So adjust the SNS index ... //we need to take into account that the same node might be removed (in case of an reorder to the end) int numSnsInRemoved = (changedChildren != null && changedChildren.getRemovals().contains(key)) ? 1 : 0; ref = ref.with(numSnsInPersisted + ref.getSnsIndex() - numSnsInRemoved); } } else if (changedChildren != null && changedChildren.insertionCount() > 0) { //it's not in the appended list, so check if there are any transient reordered nodes - appended and //reordered at the same time - they would not appear in the "appended" list ref = changedChildren.inserted(key); } } } return ref; } @Override public Iterator iterator( Name name, Context context ) { if (changedChildren != null) context = new WithChanges(context, changedChildren); return createIterator(name, context); } protected Iterator createIterator( final Name name, final Context context ) { Iterator firstIter = persisted.iterator(name, context); final MutableChildReferences appended = this.appended; Iterable second = new Iterable() { @Override public Iterator iterator() { return appended.iterator(context, name); } }; return appended == null ? firstIter : new UnionIterator(firstIter, second); } @Override public Iterator iterator( Context context ) { if (changedChildren != null) context = new WithChanges(context, changedChildren); return createIterator(context); } protected Iterator createIterator( final Context context ) { Iterator firstIter = persisted.iterator(context); final MutableChildReferences appended = this.appended; Iterable second = new Iterable() { @Override public Iterator iterator() { return appended.iterator(context); } }; return appended == null ? firstIter : new UnionIterator(firstIter, second); } @Override public Iterator getAllKeys() { Iterator firstIter = persisted.getAllKeys(); final MutableChildReferences appended = this.appended; Iterable second = new Iterable() { @Override public Iterator iterator() { return appended.getAllKeys(); } }; return appended == null ? firstIter : new UnionIterator(firstIter, second); } @Override public StringBuilder toString( StringBuilder sb ) { Iterator iter = iterator(); if (iter.hasNext()) { sb.append(iter.next()); while (iter.hasNext()) { sb.append(", "); sb.append(iter.next()); } } return sb; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy