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

org.apache.jackrabbit.spi.commons.batch.ConsolidatingChangeLog Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.jackrabbit.spi.commons.batch;

import java.util.Iterator;
import java.util.ListIterator;

import javax.jcr.RepositoryException;

import org.apache.jackrabbit.spi.Batch;
import org.apache.jackrabbit.spi.ItemId;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.NodeId;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.PathFactory;
import org.apache.jackrabbit.spi.PropertyId;
import org.apache.jackrabbit.spi.QValue;
import org.apache.jackrabbit.spi.Tree;
import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;

/**
 * A {@link ChangeLog} implementation which does basic consolidation on its
 * {@link org.apache.jackrabbit.spi.commons.batch.Operation Operation}s. That is, cancelling
 * operations are removed if possible. In general this is not possible across
 * {@link org.apache.jackrabbit.spi.commons.batch.Operations.Move move} operations. The individual
 * {@link CancelableOperation CancelableOperation} implementations document their behavior
 * concerning cancellation.
 */
public class ConsolidatingChangeLog extends AbstractChangeLog {
    private static final PathFactory PATH_FACTORY = PathFactoryImpl.getInstance();

    /**
     * Create a new instance of a consolidating change log.
     */
    public ConsolidatingChangeLog() {
        super();
    }

    /**
     * Create a {@link Path} from the {@link NodeId} of a parent and the {@link Name} of a
     * child.
     * @param parentId  node id of the parent
     * @param name  name of the child
     * @return  the path of the item name or null if parentId's
     * path is not absolute
     * @throws RepositoryException
     */
    protected static Path getPath(NodeId parentId, Name name) throws RepositoryException {
        Path parent = parentId.getPath();
        if (!parent.isAbsolute()) {
            return null;
        }

        return PATH_FACTORY.create(parent, name, true);
    }

    /**
     * Determine the {@link Path} from an {@link ItemId}.
     * @param itemId
     * @return  path of the item itemId or null if itemId's
     * path is not absolute
     */
    protected static Path getPath(ItemId itemId) {
        Path path = itemId.getPath();
        if (path != null && !path.isAbsolute()) {
            return null;
        }
        return path;
    }

    // -----------------------------------------------------< ChangeLog >---

    public void addNode(NodeId parentId, Name nodeName, Name nodetypeName, String uuid)
            throws RepositoryException {

        addOperation(CancelableOperations.addNode(parentId, nodeName, nodetypeName, uuid));
    }

    public void addProperty(NodeId parentId, Name propertyName, QValue value) throws RepositoryException {
        addOperation(CancelableOperations.addProperty(parentId, propertyName, value));
    }

    public void addProperty(NodeId parentId, Name propertyName, QValue[] values) throws RepositoryException {
        addOperation(CancelableOperations.addProperty(parentId, propertyName, values));
    }

    public void move(NodeId srcNodeId, NodeId destParentNodeId, Name destName) throws RepositoryException {
        addOperation(CancelableOperations.move(srcNodeId, destParentNodeId, destName));
    }

    public void remove(ItemId itemId) throws RepositoryException {
        addOperation(CancelableOperations.remove(itemId));
    }

    public void reorderNodes(NodeId parentId, NodeId srcNodeId, NodeId beforeNodeId) throws RepositoryException {
        addOperation(CancelableOperations.reorderNodes(parentId, srcNodeId, beforeNodeId));
    }

    public void setMixins(NodeId nodeId, Name[] mixinNodeTypeNames) throws RepositoryException {
        addOperation(CancelableOperations.setMixins(nodeId, mixinNodeTypeNames));
    }

    public void setPrimaryType(NodeId nodeId, Name primaryNodeTypeName) throws RepositoryException {
        addOperation(CancelableOperations.setPrimaryType(nodeId, primaryNodeTypeName));
    }

    public void setValue(PropertyId propertyId, QValue value) throws RepositoryException {
        addOperation(CancelableOperations.setValue(propertyId, value));
    }

    public void setValue(PropertyId propertyId, QValue[] values) throws RepositoryException {
        addOperation(CancelableOperations.setValue(propertyId, values));
    }

    @Override
    public void setTree(NodeId parentId, Tree contentTree) throws RepositoryException {
        addOperation(CancelableOperations.setTree(parentId, contentTree));
    }

    /**
     * Determines the cancellation behavior from the list of {@link ChangeLogImpl#operations operations}
     * and the current operation op:
     * 
    *
  • When the current operation is cancelled by the last operation, the list of operations * is not modified.
  • *
  • When the current operation and the last operation cancel each other, the last operation is * removed from the list of operations.
  • *
  • When the last operation is cancelled by this operation, the last operation is removed from * the list of operations and determination of cancellation starts from scratch.
  • *
  • Otherwise add the current operation to the list of operations.
  • *
*/ @Override public void addOperation(CancelableOperation op) throws RepositoryException { CancelableOperation otherOp = op; for (OperationsBackwardWithSentinel it = new OperationsBackwardWithSentinel(); it.hasNext(); ) { CancelableOperation thisOp = it.next(); switch (thisOp.cancel(otherOp)) { case CancelableOperation.CANCEL_THIS: it.remove(); continue; case CancelableOperation.CANCEL_OTHER: return; case CancelableOperation.CANCEL_BOTH: it.remove(); return; case CancelableOperation.CANCEL_NONE: super.addOperation(otherOp); return; default: assert false : "Invalid case in switch"; } } } // -----------------------------------------------------< private >--- private class OperationsBackwardWithSentinel implements Iterator { private final ListIterator it = operations.listIterator(operations.size()); private boolean last = !it.hasPrevious(); private boolean done; public boolean hasNext() { return it.hasPrevious() || last; } public CancelableOperation next() { if (last) { done = true; return CancelableOperations.empty(); } else { CancelableOperation o = it.previous(); last = !it.hasPrevious(); return o; } } public void remove() { if (done) { throw new IllegalStateException("Cannot remove last element"); } else { it.remove(); } } } // -----------------------------------------------------< CancelableOperations >--- /** * This class represent an {@link Operation} which can be cancelled by another operation * or which cancels another operation. */ protected interface CancelableOperation extends Operation { /** * The other operation cancels this operations */ public static final int CANCEL_THIS = 0; /** * This operation cancels the other operation */ public static final int CANCEL_OTHER = 1; /** * This operation and the other operation cancel each other mutually */ public static final int CANCEL_BOTH = 2; /** * No cancellation */ public static final int CANCEL_NONE = 3; /** * Determines the cancellation behavior of the other operation * on this operation. * @param other * @return Either {@link #CANCEL_THIS}, {@link #CANCEL_OTHER}, {@link #CANCEL_OTHER} * or {@link #CANCEL_NONE} * @throws RepositoryException */ public int cancel(CancelableOperation other) throws RepositoryException; } /** * Factory for creating {@link ConsolidatingChangeLog.CancelableOperation CancelableOperation}s. * The inner classes of this class all implement the CancelableOperation interface. * * @see Operation */ protected static final class CancelableOperations { private CancelableOperations() { super(); } // -----------------------------------------------------< Empty >--- /** * An Empty operation never cancels another operation and is never * cancelled by any other operation. */ public static class Empty extends Operations.Empty implements CancelableOperation { /** * @return {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE} */ public int cancel(CancelableOperation other) throws RepositoryException { return CANCEL_NONE; } } /** * Factory method for creating an {@link Empty Empty} operation. * @return */ public static CancelableOperation empty() { return new Empty(); } // -----------------------------------------------------< AddNode >--- /** * An AddNode operation is is cancelled by a * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} operation higher up the tree. * The remove operation is also cancelled if it is targeted at the same node than this add * operation. */ public static class AddNode extends Operations.AddNode implements CancelableOperation { public AddNode(NodeId parentId, Name nodeName, Name nodetypeName, String uuid) { super(parentId, nodeName, nodetypeName, uuid); } /** * @return *
    *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_BOTH CANCEL_BOTH} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has this node * as target.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_THIS CANCEL_THIS} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has an node higher up * the hierarchy as target.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} otherwise.
  • *
*/ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(parentId, nodeName); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { return CANCEL_BOTH; } return (thisPath.isDescendantOf(otherPath)) ? CANCEL_THIS : CANCEL_NONE; } return CANCEL_NONE; } } /** * Factory method for creating an {@link AddNode AddNode} operation. * @see Batch#addNode(NodeId, Name, Name, String) * * @param parentId * @param nodeName * @param nodetypeName * @param uuid * @return */ public static CancelableOperation addNode(NodeId parentId, Name nodeName, Name nodetypeName, String uuid) { return new AddNode(parentId, nodeName, nodetypeName, uuid); } // ---------------------------------------------------< AddProperty >--- /** * AddProperty operations might cancel with * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and * {@link ConsolidatingChangeLog.CancelableOperations.SetValue SetValue} operations. */ public static class AddProperty extends Operations.AddProperty implements CancelableOperation { public AddProperty(NodeId parentId, Name propertyName, QValue value) { super(parentId, propertyName, value); } public AddProperty(NodeId parentId, Name propertyName, QValue[] values) { super(parentId, propertyName, values); } /** * @return *
    *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_BOTH CANCEL_BOTH} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has this property as * target or if other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.SetValue SetValue} for a value of * null and has this property as target.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_THIS CANCEL_THIS} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has a node higher up * the hierarchy as target.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_OTHER CANCEL_OTHER} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.SetValue SetValue} and has this * property as target.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} otherwise.
  • *
*/ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(parentId, propertyName); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { return CANCEL_BOTH; } return (thisPath.isDescendantOf(otherPath)) ? CANCEL_THIS : CANCEL_NONE; } if (other instanceof SetValue) { SetValue setValue = (SetValue) other; Path thisPath = ConsolidatingChangeLog.getPath(parentId, propertyName); Path otherPath = ConsolidatingChangeLog.getPath(setValue.propertyId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { if (!isMultivalued && setValue.values[0] == null) { return CANCEL_BOTH; } else if (values.length == setValue.values.length) { for (int k = 0; k < values.length; k++) { if (!values[k].equals(setValue.values[k])) { return CANCEL_NONE; } } return CANCEL_OTHER; } } } return CANCEL_NONE; } } /** * Factory method for creating an {@link AddProperty AddProperty} operation. * * @see Batch#addProperty(NodeId, Name, QValue) * @param parentId * @param propertyName * @param value * @return */ public static CancelableOperation addProperty(NodeId parentId, Name propertyName, QValue value) { return new AddProperty(parentId, propertyName, value); } /** * Factory method for creating an {@link AddProperty AddProperty} operation. * * @see Batch#addProperty(NodeId, Name, QValue[]) * @param parentId * @param propertyName * @param values * @return */ public static CancelableOperation addProperty(NodeId parentId, Name propertyName, QValue[] values) { return new AddProperty(parentId, propertyName, values); } // ----------------------------------------------------------< Move >--- /** * An Move operation never cancels another operation and is never * cancelled by any other operation. */ public static class Move extends Operations.Move implements CancelableOperation { public Move(NodeId srcNodeId, NodeId destParentNodeId, Name destName) { super(srcNodeId, destParentNodeId, destName); } /** * @return {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} */ public int cancel(CancelableOperation other) { return CANCEL_NONE; } } /** * Factory method for creating a {@link Move Move} operation. * * @see Batch#move(NodeId, NodeId, Name) * @param srcNodeId * @param destParentNodeId * @param destName * @return */ public static CancelableOperation move(NodeId srcNodeId, NodeId destParentNodeId, Name destName) { return new Move(srcNodeId, destParentNodeId, destName); } // --------------------------------------------------------< Remove >--- /** * An Remove operation never cancels another operation and is never * cancelled by any other operation. */ public static class Remove extends Operations.Remove implements CancelableOperation { public Remove(ItemId itemId) { super(itemId); } /** * @return {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} */ public int cancel(CancelableOperation other) { return CANCEL_NONE; } } /** * Factory method for creating a {@link Remove Remove} operation. * * @see Batch#move(NodeId, NodeId, Name) * @param itemId * @return */ public static CancelableOperation remove(ItemId itemId) { return new Remove(itemId); } // -------------------------------------------------< Reorder Nodes >--- /** * A ReorderNodes operation might cancel with * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and * {@link ConsolidatingChangeLog.CancelableOperations.ReorderNodes ReorderNodes} operations. */ public static class ReorderNodes extends Operations.ReorderNodes implements CancelableOperation { public ReorderNodes(NodeId parentId, NodeId srcNodeId, NodeId beforeNodeId) { super(parentId, srcNodeId, beforeNodeId); } /** * @return *
    *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_THIS CANCEL_THIS} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has an node higher up * the hierarchy or this node as target. Or if other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.ReorderNodes ReorderNodes} which * has this node as target and neither srcNodeId nor beforeNodeId * has same name siblings.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} otherwise.
  • *
*/ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(srcNodeId); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } return thisPath.isDescendantOf(otherPath) || thisPath.equals(otherPath) ? CANCEL_THIS : CANCEL_NONE; } if (other instanceof ReorderNodes) { Path thisPath = ConsolidatingChangeLog.getPath(parentId); Path otherPath = ConsolidatingChangeLog.getPath(((ReorderNodes) other).parentId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } return thisPath.equals(otherPath) && !hasSNS(srcNodeId) && !hasSNS(beforeNodeId) ? CANCEL_THIS : CANCEL_NONE; } return CANCEL_NONE; } private boolean hasSNS(NodeId nodeId) { if (nodeId != null) { Path path = ConsolidatingChangeLog.getPath(nodeId); return path != null && path.getIndex() > 1; } return false; } } /** * Factory method for creating a {@link ReorderNodes ReorderNodes} operation. * * @see Batch#reorderNodes(NodeId, NodeId, NodeId) * @param parentId * @param srcNodeId * @param beforeNodeId * @return */ public static CancelableOperation reorderNodes(NodeId parentId, NodeId srcNodeId, NodeId beforeNodeId) { return new ReorderNodes(parentId, srcNodeId, beforeNodeId); } // -----------------------------------------------------< SetMixins >--- /** * A SetMixins operation might cancel with * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and * {@link ConsolidatingChangeLog.CancelableOperations.SetMixins SetMixins} operations. */ public static class SetMixins extends Operations.SetMixins implements CancelableOperation { public SetMixins(NodeId nodeId, Name[] mixinNodeTypeNames) { super(nodeId, mixinNodeTypeNames); } /** * @return *
    *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_THIS CANCEL_THIS} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has an node higher up * the hierarchy or this node as target. Or if other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.SetMixins SetMixins} which has this node * as target and has the same mixinNodeTypeNames.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} otherwise.
  • *
*/ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(nodeId); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } return thisPath.isDescendantOf(otherPath) || thisPath.equals(otherPath) ? CANCEL_THIS : CANCEL_NONE; } if (other instanceof SetMixins) { SetMixins setMixin = (SetMixins) other; if (mixinNodeTypeNames.length == setMixin.mixinNodeTypeNames.length) { Path thisPath = ConsolidatingChangeLog.getPath(nodeId); Path otherPath = ConsolidatingChangeLog.getPath(setMixin.nodeId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { for (int k = 0; k < mixinNodeTypeNames.length; k++) { if (!mixinNodeTypeNames[k].equals(setMixin.mixinNodeTypeNames[k])) { return CANCEL_NONE; } } return CANCEL_THIS; } } } return CANCEL_NONE; } } /** * Factory method for creating a {@link SetMixins} operation. * * @see Batch#setMixins(NodeId, Name[]) * @param nodeId * @param mixinNodeTypeNames * @return */ public static CancelableOperation setMixins(NodeId nodeId, Name[] mixinNodeTypeNames) { return new SetMixins(nodeId, mixinNodeTypeNames); } // -----------------------------------------------------< SetMixins >--- /** * A SetPrimaryType operation might cancel with * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and * {@link ConsolidatingChangeLog.CancelableOperations.SetPrimaryType SetPrimaryType} operations. */ public static class SetPrimaryType extends Operations.SetPrimaryType implements CancelableOperation { public SetPrimaryType(NodeId nodeId, Name primaryTypeName) { super(nodeId, primaryTypeName); } /** * @return *
    *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_THIS CANCEL_THIS} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has an node higher up * the hierarchy or this node as target. Or if other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.SetMixins SetMixins} which has this node * as target and has the same mixinNodeTypeNames.
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} otherwise.
  • *
*/ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(nodeId); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } return thisPath.isDescendantOf(otherPath) || thisPath.equals(otherPath) ? CANCEL_THIS : CANCEL_NONE; } if (other instanceof SetPrimaryType) { SetPrimaryType setPrimaryType = (SetPrimaryType) other; if (primaryTypeName.equals(setPrimaryType.primaryTypeName)) { Path thisPath = ConsolidatingChangeLog.getPath(nodeId); Path otherPath = ConsolidatingChangeLog.getPath(setPrimaryType.nodeId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { return CANCEL_THIS; } } } return CANCEL_NONE; } } /** * Factory method for creating a {@link SetPrimaryType} operation. * * @see Batch#setPrimaryType(NodeId, Name) * @param nodeId * @param primaryTypeName * @return */ public static CancelableOperation setPrimaryType(NodeId nodeId, Name primaryTypeName) { return new SetPrimaryType(nodeId, primaryTypeName); } // ------------------------------------------------------< SetValue >--- /** * A SetValue operation might cancel with * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and * {@link ConsolidatingChangeLog.CancelableOperations.SetValue SetValue} operations. */ public static class SetValue extends Operations.SetValue implements CancelableOperation { public SetValue(PropertyId propertyId, QValue value) { super(propertyId, value); } public SetValue(PropertyId propertyId, QValue[] values) { super(propertyId, values); } /** * @return *
    *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_THIS CANCEL_THIS} if * other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.Remove Remove} and has an node higher up * the hierarchy or this node as target. Or if other is an instance of * {@link ConsolidatingChangeLog.CancelableOperations.SetValue SetValue} which has this * property as target
  • *
  • {@link ConsolidatingChangeLog.CancelableOperation#CANCEL_NONE CANCEL_NONE} otherwise.
  • *
*/ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(propertyId); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } return thisPath.isDescendantOf(otherPath) || thisPath.equals(otherPath) ? CANCEL_THIS : CANCEL_NONE; } if (other instanceof SetValue) { Path thisPath = ConsolidatingChangeLog.getPath(propertyId); Path otherPath = ConsolidatingChangeLog.getPath(((SetValue) other).propertyId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { return CANCEL_THIS; } } return CANCEL_NONE; } } /** * Factory method for creating a {@link SetValue SetValue} operation. * * @see Batch#setValue(PropertyId, QValue) * @param propertyId * @param value * @return */ public static CancelableOperation setValue(PropertyId propertyId, QValue value) { return new SetValue(propertyId, value); } /** * Factory method for creating a {@link SetValue SetValue} operation. * * @see Batch#setValue(PropertyId, QValue[]) * @param propertyId * @param values * @return */ public static CancelableOperation setValue(PropertyId propertyId, QValue[] values) { return new SetValue(propertyId, values); } //--------------------------------------------------------< SetTree >--- public static class SetTree extends Operations.SetTree implements CancelableOperation { public SetTree(NodeId parentId, Tree contentTree) { super(parentId, contentTree); } /** * The cancellation only considers canceling the parent node, which corresponds * to the policy node. */ public int cancel(CancelableOperation other) throws RepositoryException { if (other instanceof Remove) { Path thisPath = ConsolidatingChangeLog.getPath(parentId, tree.getName()); Path otherPath = ConsolidatingChangeLog.getPath(((Remove) other).itemId); if (thisPath == null || otherPath == null) { return CANCEL_NONE; } if (thisPath.equals(otherPath)) { return CANCEL_BOTH; } return (thisPath.isDescendantOf(otherPath)) ? CANCEL_THIS : CANCEL_NONE; } return CANCEL_NONE; } } /** * Factory method for creating an {@link SetTree} operation. * @see Batch#setTree(NodeId, Tree) * * @param parentId * @param tree * @return */ public static CancelableOperation setTree(NodeId parentId, Tree tree) { return new SetTree(parentId, tree); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy