org.modeshape.jcr.cache.ChildReferences Maven / Gradle / Ivy
/*
* 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;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.modeshape.common.annotation.Immutable;
import org.modeshape.common.annotation.NotThreadSafe;
import org.modeshape.common.annotation.ThreadSafe;
import org.modeshape.common.collection.EmptyIterator;
import org.modeshape.jcr.cache.document.WorkspaceCache;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.NamespaceRegistry;
import org.modeshape.jcr.value.Path.Segment;
/**
* An interface used to access the {@link ChildReference} instances owned by a parent node.
*/
@Immutable
public interface ChildReferences extends Iterable {
/**
* A constant that might be returned by {@link #size()} if the number of child references is unknown.
*/
static final long UNKNOWN_SIZE = -1L;
/**
* Get the total number of child references for the node, including all subsequent blocks of ChildReferences.
*
* @return the total number of children, or {@link #UNKNOWN_SIZE}
*/
long size();
/**
* Determine if there are no references in this container. This is equivalent to calling {@code size() == 0} but may be
* faster.
*
* @return true if there are no references in this container, or false if there are.
*/
boolean isEmpty();
/**
* Return the number of nodes that have the supplied name. If there are no siblings with the same supplied name, this method
* will return 1; otherwise it will return the number of same-name-siblings.
*
* @param name the name
* @return the number of siblings with the supplied name; never negative
*/
int getChildCount( Name name );
/**
* Look for the child reference that has the given name and a SNS index of '1'.
*
* @param name the name for the node
* @return the child reference, or null if there is no such child
*/
ChildReference getChild( Name name );
/**
* Look for the child reference that has the given name and SNS index.
*
* @param name the name for the node
* @param snsIndex the same-name-sibling index; must be positive
* @return the child reference, or null if there is no such child
*/
ChildReference getChild( Name name,
int snsIndex );
/**
* Look for the child reference that has the given name and SNS index.
*
* @param name the name for the node
* @param snsIndex the same-name-sibling index; must be positive
* @param context the context in which the child should be evaluated; may be null if there is no context
* @return the child reference, or null if there is no such child
*/
ChildReference getChild( Name name,
int snsIndex,
Context context );
/**
* Look for the child reference that has the given name and SNS index.
*
* @param segment the path segment, which defines the name and SNS index
* @return the child reference, or null if there is no such child
*/
ChildReference getChild( Segment segment );
/**
* Determine if this contains a reference to the specified child.
*
* @param key the node key of the child
* @return true if there is a child reference, or false if there is none
*/
boolean hasChild( NodeKey key );
/**
* Look for the child reference that has the node key.
*
* @param key the node key of the child
* @return the child reference, or null if there is no such child
*/
ChildReference getChild( NodeKey key );
/**
* Look for the child reference that has the node key.
*
* @param key the node key of the child
* @param context the context in which the child should be evaluated; may be null if there is no context
* @return the child reference, or null if there is no such child
*/
ChildReference getChild( NodeKey key,
Context context );
/**
* Return whether it is possible/feasible to {@link #getChild(NodeKey, Context) find} a ChildReference for a child node given
* only its NodeKey. Implementations that have very large numbers of children may provide an alternative way to
* {@link WorkspaceCache#getChildReference(NodeKey,NodeKey) lookup} a child reference directly. In such cases, this method may
* return false.
*
* @return true if {@link #getChild(NodeKey)} and {@link #getChild(NodeKey, Context)} should be used to find the
* ChildReference, or false if doing so is not recommended.
*/
boolean supportsGetChildReferenceByKey();
/**
* Get an iterator over all of the children that have same name matching the supplied value. This essentially returns an
* iterator over all of the same-name-siblings.
*
* @param name the name of the same-name-sibling nodes; may not be null
* @return the iterator; never null
*/
Iterator iterator( Name name );
/**
* Get an iterator over all of the children that have same name matching the supplied value. This essentially returns an
* iterator over all of the same-name-siblings.
*
* @param name the name of the same-name-sibling nodes; may not be null
* @param context the context in which the child should be evaluated; may be null if there is no context
* @return the iterator; never null
*/
Iterator iterator( Name name,
Context context );
/**
* Get an iterator over all of the children.
*
* @return the iterator; never null
*/
@Override
Iterator iterator();
/**
* Get an iterator over all of the children that have {@link Segment#getName() names} (excluding same-name-sibling indexes)
* matching at least one of the supplied patterns.
*
* @param namePatterns the list of string literals or regex patterns describing the names
* @param registry the namespace registry, used to convert names to a form compatible with the name patterns
* @return the iterator; never null
*/
Iterator iterator( Collection> namePatterns,
NamespaceRegistry registry );
/**
* Get an iterator over all child references in this collection, using the supplied context.
*
* @param context the context in which the child should be evaluated; may be null if there is no context
* @return the iterator over all references; never null
*/
Iterator iterator( Context context );
/**
* Get an iterator over all of the children that have {@link Segment#getName() names} (excluding same-name-sibling indexes)
* matching at least one of the supplied patterns, using the supplied context. The resulting iterator is lazy where possible,
* but it may be an expensive call if there are large numbers of children.
*
* @param context the context in which the child should be evaluated; may be null if there is no context
* @param namePatterns the list of string literals or regex patterns describing the names
* @param registry the namespace registry, used to convert names to a form compatible with the name patterns
* @return the iterator; never null
*/
Iterator iterator( Context context,
Collection> namePatterns,
NamespaceRegistry registry );
/**
* Get the keys for all of the children. The resulting iterator is lazy where possible, but it may be an expensive call if
* there are large numbers of children.
*
* @return the iterator over the keys; never null
*/
Iterator getAllKeys();
/**
* The context in which the names are evaluated.
*/
interface Context {
/**
* Consume the next child with the supplied name and key.
*
* @param name the name of the node; may not be null
* @param key the key for the node; may not be null
* @return the same-name-sibling index for this node; always positive
*/
int consume( Name name,
NodeKey key );
/**
* Get the set of changes for this context.
*
* @return the changes; never null
*/
Changes changes();
}
/**
* The representation of a set of changes for the child references.
*/
interface Changes {
/**
* Get the references to the children with the supplied name that were inserted.
*
* @param name the name; may not be null
* @return the iterator over the insertions; never null but possibly empty
*/
Iterator insertions( Name name );
/**
* Get the child reference for the inserted node with the supplied key.
*
* @param key the node key for the inserted node; may not be null
* @return the child reference, or null if no node was inserted with the supplied key
*/
ChildReference inserted( NodeKey key );
/**
* Get the set of child references that were inserted before the node with the supplied key.
*
* @param key the node key for the node before which the inserted nodes are to be returned; may not be null
* @return the nodes that were inserted before the node with the supplied key
*/
ChildInsertions insertionsBefore( ChildReference key );
/**
* Determine whether the supplied child reference was removed.
*
* @param ref the reference; may not be null
* @return true if the child reference was removed, or false otherwise
*/
boolean isRemoved( ChildReference ref );
/**
* Determine whether the supplied child reference was renamed.
*
* @param ref the reference; may not be null
* @return true if the child reference was renamed, or false otherwise
*/
boolean isRenamed( ChildReference ref );
/**
* Determine whether any of the child references were renamed to the supplied name.
*
* @param newName the new name; may not be null
* @return true if at least one child reference was renamed to the supplied name, or false otherwise
*/
boolean isRenamed( Name newName );
/**
* Return the new name for the child node with the supplied key.
*
* @param key the child node's key; may not be null
* @return the new name, or null if the node is not a child or was not renamed
*/
Name renamed( NodeKey key );
/**
* Determine if this set of changes is empty.
*
* @return true if there are no effective changes, or false if there is at least one effective change
*/
boolean isEmpty();
/**
* Get the number of child references that were removed.
*
* @return the number of removed child references; never negative
*/
int removalCount();
/**
* Get the number of child references that were inserted.
*
* @return the number of inserted child references; never negative
*/
int insertionCount();
/**
* Get the number of child references that were inserted with the given name.
*
* @param name the {@link Name} of a child, never {@code null}
* @return the number of inserted child references which have the given name; never negative
*/
int insertionCount( Name name );
/**
* Get the number of child references that were renamed.
*
* @return the number of renamed child references; never negative
*/
int renameCount();
}
/**
* A representation of the child references that were inserted before some other node.
*/
interface ChildInsertions {
/**
* The nodes that were inserted.
*
* @return the iterator over the child references that were inserted; never null
*/
Iterable inserted();
/**
* The reference to the child before which the nodes are to be inserted.
*
* @return the child reference before which the nodes are to be inserted; never null
*/
ChildReference insertedBefore();
}
/**
* A {@link ChildReferences.Changes} implementation that has no changes and that is useful when there are never any siblings
* with the same names, since it always returns '1' for the SNS index.
*/
public static final class NoContext implements Context {
protected static final Context INSTANCE = new NoContext();
private NoContext() {
}
@Override
public int consume( Name name,
NodeKey key ) {
return 1;
}
@Override
public Changes changes() {
return null;
}
}
@Immutable
public static final class NoChanges implements Changes {
protected static final Iterator NO_INSERTIONS_ITERATOR = new EmptyIterator();
@Override
public boolean isEmpty() {
return true;
}
@Override
public int insertionCount() {
return 0;
}
@Override
public int insertionCount( Name name ) {
return 0;
}
@Override
public int removalCount() {
return 0;
}
@Override
public int renameCount() {
return 0;
}
@Override
public Name renamed( NodeKey key ) {
return null;
}
@Override
public Iterator insertions( Name name ) {
return NO_INSERTIONS_ITERATOR;
}
@Override
public ChildReference inserted( NodeKey key ) {
return null;
}
@Override
public ChildInsertions insertionsBefore( ChildReference key ) {
return null;
}
@Override
public boolean isRemoved( ChildReference key ) {
return false;
}
@Override
public boolean isRenamed( ChildReference ref ) {
return false;
}
@Override
public boolean isRenamed( Name newName ) {
return false;
}
}
/**
* A {@link ChildReferences.Context} implementation that has no changes and that always returns '1' for the SNS index.
*/
@ThreadSafe
public static final class NoSnsIndexesContext implements Context {
@Override
public int consume( Name name,
NodeKey key ) {
return 1;
}
@Override
public Changes changes() {
return null;
}
}
/**
* A {@link ChildReferences.Context} implementation that has no changes and can be used to find the SNS indexes for nodes
* named a single name.
*/
@ThreadSafe
public static class SingleNameContext implements Context {
private int index = 0;
@Override
public int consume( Name name,
NodeKey key ) {
return ++index;
}
@Override
public Changes changes() {
return null;
}
}
/**
* A {@link ChildReferences.Context} implementation that has no changes but maintains the SNS indexes for nodes with any name.
*/
@NotThreadSafe
public static class BasicContext implements Context {
private final Map indexes = new HashMap();
@Override
public int consume( Name name,
NodeKey key ) {
AtomicInteger index = indexes.get(name);
if (index == null) {
index = new AtomicInteger(1);
indexes.put(name, index);
return 1;
}
return index.incrementAndGet();
}
@Override
public Changes changes() {
return null;
}
}
/**
* A {@link ChildReferences.Context} implementation that has changes and can be used to find the SNS indexes for nodes named a
* single name.
*/
@ThreadSafe
public static class WithChanges implements Context {
private final Context delegate;
private final Changes changes;
public WithChanges( Context delegate,
Changes changes ) {
this.delegate = delegate;
this.changes = changes;
}
@Override
public int consume( Name name,
NodeKey key ) {
return this.delegate.consume(name, key);
}
@Override
public Changes changes() {
return changes;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy