org.modeshape.jcr.index.local.IndexChangeAdapters 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.index.local;
import java.util.Map;
import java.util.Set;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.JcrLexicon;
import org.modeshape.jcr.cache.CachedNode.Properties;
import org.modeshape.jcr.cache.NodeKey;
import org.modeshape.jcr.cache.change.AbstractPropertyChange;
import org.modeshape.jcr.cache.change.ChangeSetAdapter.NodeTypePredicate;
import org.modeshape.jcr.cache.change.PropertyAdded;
import org.modeshape.jcr.cache.change.PropertyChanged;
import org.modeshape.jcr.cache.change.PropertyRemoved;
import org.modeshape.jcr.spi.index.provider.IndexChangeAdapter;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.Path;
import org.modeshape.jcr.value.Property;
import org.modeshape.jcr.value.ValueFactory;
/**
* Utility for creating {@link IndexChangeAdapter} instances.
*
* @author Randall Hauch ([email protected])
*/
public class IndexChangeAdapters {
/**
* Create an {@link IndexChangeAdapter} implementation that handles the "mode:nodeDepth" property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forNodeDepth( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
return new NodeDepthChangeAdapter(context, matcher, workspaceName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles the "jcr:name" property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forNodeName( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
return new NodeNameChangeAdapter(context, matcher, workspaceName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles the "mode:localName" property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forNodeLocalName( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
return new NodeLocalNameChangeAdapter(context, matcher, workspaceName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles the "jcr:path" property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forNodePath( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
return new NodePathChangeAdapter(context, matcher, workspaceName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles the "jcr:primaryType" property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forPrimaryType( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
return new PrimaryTypeChangeAdatper(context, matcher, workspaceName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles the "jcr:mixinTypes" property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forMixinTypes( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
return new MixinTypesChangeAdatper(context, matcher, workspaceName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles a single-valued property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param propertyName the name of the property; may not be null
* @param factory the value factory for the property's value type; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forSingleValuedProperty( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory factory,
LocalDuplicateIndex index ) {
return new SingleValuedPropertyChangeAdapter(context, matcher, workspaceName, propertyName, factory, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles a multi-valued property.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param propertyName the name of the property; may not be null
* @param factory the value factory for the property's value type; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forMultiValuedProperty( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory factory,
LocalDuplicateIndex index ) {
return new MultiValuedPropertyChangeAdapter(context, matcher, workspaceName, propertyName, factory, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles a unique-valued property, where every property value is
* unique across all nodes.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param propertyName the name of the property; may not be null
* @param factory the value factory for the property's value type; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forUniqueValuedProperty( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory factory,
LocalUniqueIndex index ) {
return new UniquePropertyChangeAdapter(context, matcher, workspaceName, propertyName, factory, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles a single-valued enumerated property. Because all
* enumerated values are distinct, they are treated as strings.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param propertyName the name of the property; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forSingleValuedEnumeratedProperty( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
LocalEnumeratedIndex index ) {
return new SingleValuedEnumeratedPropertyChangeAdapter(context, matcher, workspaceName, propertyName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles a multi-valued enumerated property. Because all enumerated
* values are distinct, they are treated as strings.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param propertyName the name of the property; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forMultiValuedEnumeratedProperty( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
LocalEnumeratedIndex index ) {
return new MultiValuedEnumeratedPropertyChangeAdapter(context, matcher, workspaceName, propertyName, index);
}
/**
* Create an {@link IndexChangeAdapter} implementation that handles node type information.
*
* @param context the execution context; may not be null
* @param matcher the node type matcher used to determine which nodes should be included in the index; may not be null
* @param workspaceName the name of the workspace; may not be null
* @param index the local index that should be used; may not be null
* @return the new {@link IndexChangeAdapter}; never null
*/
public static IndexChangeAdapter forNodeTypes( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalIndex index ) {
return new NodeTypesChangeAdapter(context, matcher, workspaceName, index);
}
private IndexChangeAdapters() {
}
protected static abstract class PathBasedChangeAdapter extends IndexChangeAdapter {
private final LocalDuplicateIndex index;
private final boolean includeRoot;
protected PathBasedChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index,
boolean includeRoot ) {
super(context, workspaceName, matcher);
this.index = index;
this.includeRoot = includeRoot;
}
protected abstract T convertRoot( Path path );
protected abstract T convert( Path path );
@Override
protected void addNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
if (path.isRoot() && includeRoot) {
index.add(nodeKey(key), convertRoot(path));
} else {
index.add(nodeKey(key), convert(path));
}
}
@Override
protected void reindexNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
if (path.isRoot() && includeRoot) {
index.add(nodeKey(key), convertRoot(path));
} else {
index.add(nodeKey(key), convert(path));
}
}
@Override
protected void moveNode( String workspaceName,
NodeKey key,
Name primaryType,
Set mixinTypes,
NodeKey oldParent,
NodeKey newParent,
Path newPath,
Path oldPath,
boolean queryable ) {
String nodeKey = nodeKey(key);
if (includeRoot) {
if (oldPath.isRoot()) index.remove(nodeKey);
if (newPath.isRoot()) index.add(nodeKey, convertRoot(newPath));
} else {
if (!oldPath.isRoot()) index.remove(nodeKey);
if (!newPath.isRoot()) index.add(nodeKey, convertRoot(newPath));
}
}
@Override
protected void removeNode( String workspaceName,
NodeKey key,
NodeKey parentKey,
Path path,
Name primaryType,
Set mixinTypes,
boolean queryable ) {
if (includeRoot || path.isRoot()) {
index.remove(nodeKey(key));
}
}
@Override
protected void completeChanges() {
index.commit();
super.completeChanges();
}
@Override
protected void completeWorkspaceChanges() {
index.commit();
super.completeWorkspaceChanges();
}
@Override
public String toString() {
return getClass().getSimpleName() + "(\"" + index.getName() + "\")";
}
}
protected static final class NodeDepthChangeAdapter extends PathBasedChangeAdapter {
public NodeDepthChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, index, true);
}
@Override
protected Long convert( Path path ) {
return (long)path.size();
}
@Override
protected Long convertRoot( Path path ) {
return (long)path.size();
}
}
protected static final class NodeNameChangeAdapter extends PathBasedChangeAdapter {
public NodeNameChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, index, true);
}
@Override
protected Name convert( Path path ) {
return path.getLastSegment().getName();
}
@Override
protected Name convertRoot( Path path ) {
return Path.ROOT_NAME;
}
}
protected static final class NodeLocalNameChangeAdapter extends PathBasedChangeAdapter {
public NodeLocalNameChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, index, true);
}
@Override
protected String convert( Path path ) {
return path.getLastSegment().getName().getLocalName();
}
@Override
protected String convertRoot( Path path ) {
return "";
}
}
protected static final class NodePathChangeAdapter extends PathBasedChangeAdapter {
public NodePathChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, index, true);
}
@Override
protected Path convert( Path path ) {
return path;
}
@Override
protected Path convertRoot( Path path ) {
return path;
}
}
protected static String nodeKey( NodeKey key ) {
return key.toString();
}
protected static abstract class AbstractPropertyChangeAdapter extends IndexChangeAdapter {
protected final Name propertyName;
protected final ValueFactory valueFactory;
public AbstractPropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory valueFactory ) {
super(context, workspaceName, matcher);
this.propertyName = propertyName;
this.valueFactory = valueFactory;
}
protected final T convert( Object value ) {
return valueFactory.create(value);
}
protected abstract void addValues( NodeKey key,
Property property );
protected abstract void addValue( NodeKey key,
Object value );
protected abstract void removeValues( NodeKey key );
@Override
protected void addNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
// Properties on new nodes are always represented as 'PropertyAdded' events, and handled via 'modifyProperties' ...
// Property prop = properties.getProperty(propertyName);
// if (prop != null) {
// addValues(key, prop);
// }
}
@Override
protected void reindexNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
if (properties != null) {
assert propertyName != null;
Property prop = properties.getProperty(propertyName);
if (prop != null) {
removeValues(key);
addValues(key, prop);
}
}
}
@Override
protected void modifyProperties( NodeKey key,
Map propChanges ) {
AbstractPropertyChange propChange = propChanges.get(propertyName);
if (propChange instanceof PropertyChanged) {
PropertyChanged change = (PropertyChanged)propChange;
removeValues(key);
addValues(key, change.getNewProperty());
} else if (propChange instanceof PropertyAdded) {
PropertyAdded added = (PropertyAdded)propChange;
removeValues(key);
addValues(key, added.getProperty());
} else if (propChange instanceof PropertyRemoved) {
removeValues(key);
}
}
@Override
protected void removeNode( String workspaceName,
NodeKey key,
NodeKey parentKey,
Path path,
Name primaryType,
Set mixinTypes,
boolean queryable ) {
removeValues(key);
}
}
protected static abstract class PropertyChangeAdapter extends AbstractPropertyChangeAdapter {
protected final LocalDuplicateIndex index;
public PropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory valueFactory,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, propertyName, valueFactory);
this.index = index;
}
@Override
protected void addValues( NodeKey key,
Property property ) {
for (Object value : property) {
index.add(nodeKey(key), convert(value));
}
}
@Override
protected final void addValue( NodeKey key,
Object value ) {
index.add(nodeKey(key), convert(value));
}
@Override
protected void removeValues( NodeKey key ) {
index.remove(nodeKey(key));
}
@Override
protected void completeChanges() {
index.commit();
super.completeChanges();
}
@Override
protected void completeWorkspaceChanges() {
index.commit();
super.completeWorkspaceChanges();
}
@Override
public String toString() {
return getClass().getSimpleName() + "(\"" + index.getName() + "\")";
}
}
protected static final class SingleValuedPropertyChangeAdapter extends PropertyChangeAdapter {
public SingleValuedPropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory valueFactory,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, propertyName, valueFactory, index);
}
@Override
protected void addValues( NodeKey key,
Property property ) {
index.add(nodeKey(key), convert(property.getFirstValue()));
}
}
protected static final class MultiValuedPropertyChangeAdapter extends PropertyChangeAdapter {
public MultiValuedPropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory valueFactory,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, propertyName, valueFactory, index);
}
}
protected static final class PrimaryTypeChangeAdatper extends PropertyChangeAdapter {
public PrimaryTypeChangeAdatper( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, JcrLexicon.PRIMARY_TYPE, context.getValueFactories().getNameFactory(), index);
}
@Override
protected void addNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
addValue(key, primaryType);
}
}
protected static final class MixinTypesChangeAdatper extends PropertyChangeAdapter {
public MixinTypesChangeAdatper( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalDuplicateIndex index ) {
super(context, matcher, workspaceName, JcrLexicon.MIXIN_TYPES, context.getValueFactories().getNameFactory(), index);
}
@Override
protected void addNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
if (mixinTypes != null && !mixinTypes.isEmpty()) {
for (Name mixinType : mixinTypes) {
addValue(key, mixinType);
}
}
}
}
protected static final class UniquePropertyChangeAdapter extends AbstractPropertyChangeAdapter {
protected final LocalUniqueIndex index;
public UniquePropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
ValueFactory valueFactory,
LocalUniqueIndex index ) {
super(context, matcher, workspaceName, propertyName, valueFactory);
this.index = index;
}
@Override
protected void addValues( NodeKey key,
Property property ) {
index.add(nodeKey(key), convert(property.getFirstValue()));
}
@Override
protected final void addValue( NodeKey key,
Object value ) {
index.add(nodeKey(key), convert(value));
}
@Override
protected void removeValues( NodeKey key ) {
index.remove(nodeKey(key));
}
@Override
protected void completeChanges() {
index.commit();
super.completeChanges();
}
@Override
protected void completeWorkspaceChanges() {
index.commit();
super.completeWorkspaceChanges();
}
@Override
public String toString() {
return getClass().getSimpleName() + "(\"" + index.getName() + "\")";
}
}
protected static abstract class EnumeratedPropertyChangeAdapter extends AbstractPropertyChangeAdapter {
protected final LocalIndex index;
public EnumeratedPropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
LocalIndex index ) {
super(context, matcher, workspaceName, propertyName, context.getValueFactories().getStringFactory());
this.index = index;
}
@Override
protected void addValues( NodeKey key,
Property property ) {
for (Object value : property) {
index.add(nodeKey(key), convert(value));
}
}
@Override
protected final void addValue( NodeKey key,
Object value ) {
index.add(nodeKey(key), convert(value));
}
@Override
protected void removeValues( NodeKey key ) {
index.remove(nodeKey(key));
}
@Override
protected void completeChanges() {
index.commit();
super.completeChanges();
}
@Override
protected void completeWorkspaceChanges() {
index.commit();
super.completeWorkspaceChanges();
}
@Override
public String toString() {
return getClass().getSimpleName() + "(\"" + index.getName() + "\")";
}
}
protected static final class SingleValuedEnumeratedPropertyChangeAdapter extends EnumeratedPropertyChangeAdapter {
public SingleValuedEnumeratedPropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
LocalEnumeratedIndex index ) {
super(context, matcher, workspaceName, propertyName, index);
}
@Override
protected void addValues( NodeKey key,
Property property ) {
index.add(nodeKey(key), convert(property.getFirstValue()));
}
}
protected static final class MultiValuedEnumeratedPropertyChangeAdapter extends EnumeratedPropertyChangeAdapter {
public MultiValuedEnumeratedPropertyChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
Name propertyName,
LocalEnumeratedIndex index ) {
super(context, matcher, workspaceName, propertyName, index);
}
}
protected static final class NodeTypesChangeAdapter extends EnumeratedPropertyChangeAdapter {
public NodeTypesChangeAdapter( ExecutionContext context,
NodeTypePredicate matcher,
String workspaceName,
LocalIndex index ) {
super(context, matcher, workspaceName, null, index);
}
protected final void removeValues( NodeKey key,
Property oldProperty ) {
for (Object value : oldProperty) {
removeValue(key, value);
}
}
protected final void removeValue( NodeKey key,
Object value ) {
index.remove(nodeKey(key), convert(value));
}
@Override
protected void addNode( String workspaceName,
NodeKey key,
Path path,
Name primaryType,
Set mixinTypes,
Properties properties,
boolean queryable ) {
addValue(key, primaryType);
if (!mixinTypes.isEmpty()) {
for (Name mixinType : mixinTypes) {
addValue(key, mixinType);
}
}
}
@Override
protected void modifyProperties( NodeKey key,
Map propChanges ) {
AbstractPropertyChange propChange = propChanges.get(JcrLexicon.PRIMARY_TYPE);
if (propChange instanceof PropertyChanged) {
PropertyChanged change = (PropertyChanged)propChange;
addValue(key, change.getNewProperty().getFirstValue());
removeValue(key, change.getOldProperty().getFirstValue());
}
propChange = propChanges.get(JcrLexicon.MIXIN_TYPES);
if (propChange instanceof PropertyChanged) {
PropertyChanged change = (PropertyChanged)propChange;
removeValues(key, change.getOldProperty());
addValues(key, change.getNewProperty());
}
}
@Override
protected void removeNode( String workspaceName,
NodeKey key,
NodeKey parentKey,
Path path,
Name primaryType,
Set mixinTypes,
boolean queryable ) {
removeValues(key);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy