eventstatecollection.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 570 行 · 第 1/2 页

JAVA
570
字号
/* * 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.core.observation;import org.apache.jackrabbit.core.HierarchyManager;import org.apache.jackrabbit.core.ItemId;import org.apache.jackrabbit.core.NodeId;import org.apache.jackrabbit.core.SessionImpl;import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;import org.apache.jackrabbit.core.state.ChangeLog;import org.apache.jackrabbit.core.state.ItemState;import org.apache.jackrabbit.core.state.ItemStateException;import org.apache.jackrabbit.core.state.ItemStateManager;import org.apache.jackrabbit.core.state.NoSuchItemStateException;import org.apache.jackrabbit.core.state.NodeState;import org.apache.jackrabbit.name.MalformedPathException;import org.apache.jackrabbit.name.Path;import org.apache.jackrabbit.name.QName;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.jcr.PathNotFoundException;import javax.jcr.RepositoryException;import javax.jcr.nodetype.NodeType;import javax.jcr.nodetype.NodeTypeManager;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.List;import java.util.Set;import java.util.Collections;/** * The <code>EventStateCollection</code> class implements how {@link EventState} * objects are created based on the {@link org.apache.jackrabbit.core.state.ItemState}s * passed to the {@link #createEventStates} method. * <p/> * The basic sequence of method calls is: * <ul> * <li>{@link #createEventStates} or {@link #addAll} to create or add event * states to the collection</li> * <li>{@link #prepare} or {@link #prepareDeleted} to prepare the events. If * this step is omitted, EventListeners might see events of deleted item * they are not allowed to see.</li> * <li>{@link #dispatch()} to dispatch the events to the EventListeners.</li> * </ul> */public final class EventStateCollection {    /**     * Logger instance for this class     */    private static Logger log = LoggerFactory.getLogger(EventStateCollection.class);    /**     * List of events     */    private final List events = new ArrayList();    /**     * Event dispatcher.     */    private final EventDispatcher dispatcher;    /**     * The session that created these events     */    private final SessionImpl session;    /**     * The prefix to use for the event paths or <code>null</code> if no prefix     * should be used.     */    private final Path pathPrefix;    /**     * Creates a new empty <code>EventStateCollection</code>.     * <p/>     * Because the item state manager in {@link #createEventStates} may represent     * only a subset of the over all item state hierarchy, this constructor     * also takes a path prefix argument. If non <code>null</code> all events     * created by this collection are prefixed with this path.     *     * @param dispatcher event dispatcher     * @param session    the session that created these events.     * @param pathPrefix the path to prefix the event paths or <code>null</code>     *                   if no prefix should be used.     */    public EventStateCollection(EventDispatcher dispatcher,                         SessionImpl session,                         Path pathPrefix) {        this.dispatcher = dispatcher;        this.session = session;        this.pathPrefix = pathPrefix;    }    /**     * Creates {@link EventState} instances from <code>ItemState</code>     * <code>changes</code>.     *     * @param rootNodeId   the id of the root node.     * @param changes      the changes on <code>ItemState</code>s.     * @param stateMgr     an <code>ItemStateManager</code> to provide <code>ItemState</code>     *                     of items that are not contained in the <code>changes</code> collection.     * @throws ItemStateException if an error occurs while creating events     *                            states for the item state changes.     */    public void createEventStates(NodeId rootNodeId, ChangeLog changes, ItemStateManager stateMgr) throws ItemStateException {        // create a hierarchy manager, that is based on the ChangeLog and        // the ItemStateProvider        // todo use CachingHierarchyManager ?        ChangeLogBasedHierarchyMgr hmgr = new ChangeLogBasedHierarchyMgr(                rootNodeId, stateMgr, changes, session);        /**         * Important:         * Do NOT change the sequence of events generated unless there's         * a very good reason for it! Some internal SynchronousEventListener         * implementations depend on the order of the events fired.         * LockManagerImpl for example expects that for any given path a         * childNodeRemoved event is fired before a childNodeAdded event.         */        // 1. modified items        for (Iterator it = changes.modifiedStates(); it.hasNext();) {            ItemState state = (ItemState) it.next();            if (state.isNode()) {                // node changed                // covers the following cases:                // 1) property added                // 2) property removed                // 3) child node added                // 4) child node removed                // 5) node moved                // 6) node reordered                // cases 1) and 2) are detected with added and deleted states                // on the PropertyState itself.                // cases 3) and 4) are detected with added and deleted states                // on the NodeState itself.                // in case 5) two or three nodes change. two nodes are changed                // when a child node is renamed. three nodes are changed when                // a node is really moved. In any case we are only interested in                // the node that actually got moved.                // in case 6) only one node state changes. the state of the                // parent node.                NodeState n = (NodeState) state;                if (n.hasOverlayedState()) {                    NodeId oldParentId = n.getOverlayedState().getParentId();                    NodeId newParentId = n.getParentId();                    if (newParentId != null && !oldParentId.equals(newParentId)) {                        // node moved                        // generate node removed & node added event                        NodeState oldParent;                        try {                            oldParent = (NodeState) changes.get(oldParentId);                        } catch (NoSuchItemStateException e) {                            // old parent has been deleted, retrieve from                            // shared item state manager                            oldParent = (NodeState) stateMgr.getItemState(oldParentId);                        }                        NodeTypeImpl oldParentNodeType = getNodeType(oldParent, session);                        Set mixins = oldParent.getMixinTypeNames();                        Path newPath = getPath(n.getNodeId(), hmgr);                        Path oldPath = getZombiePath(n.getNodeId(), hmgr);                        if (!oldPath.equals(newPath)) {                            events.add(EventState.childNodeRemoved(oldParentId,                                    getParent(oldPath),                                    n.getNodeId(),                                    oldPath.getNameElement(),                                    oldParentNodeType.getQName(),                                    mixins,                                    session));                            NodeState newParent = (NodeState) changes.get(newParentId);                            NodeTypeImpl newParentNodeType = getNodeType(newParent, session);                            mixins = newParent.getMixinTypeNames();                            events.add(EventState.childNodeAdded(newParentId,                                    getParent(newPath),                                    n.getNodeId(),                                    newPath.getNameElement(),                                    newParentNodeType.getQName(),                                    mixins,                                    session));                        } else {                            log.error("Unable to calculate old path of moved node");                        }                    } else {                        // a moved node always has a modified parent node                        NodeState parent = null;                        try {                            // root node does not have a parent UUID                            if (state.getParentId() != null) {                                parent = (NodeState) changes.get(state.getParentId());                            }                        } catch (NoSuchItemStateException e) {                            // should never happen actually. this would mean                            // the parent of this modified node is deleted                            String msg = "Parent of node " + state.getId() + " is deleted.";                            log.error(msg);                            throw new ItemStateException(msg, e);                        }                        if (parent != null) {                            // check if node has been renamed                            NodeState.ChildNodeEntry moved = null;                            for (Iterator removedNodes = parent.getRemovedChildNodeEntries().iterator(); removedNodes.hasNext();) {                                NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) removedNodes.next();                                if (child.getId().equals(n.getNodeId())) {                                    // found node re-added with different name                                    moved = child;                                }                            }                            if (moved != null) {                                NodeTypeImpl nodeType = getNodeType(parent, session);                                Set mixins = parent.getMixinTypeNames();                                Path newPath = getPath(state.getId(), hmgr);                                Path parentPath = getParent(newPath);                                Path oldPath;                                try {                                    if (moved.getIndex() == 0) {                                        oldPath = Path.create(parentPath, moved.getName(), false);                                    } else {                                        oldPath = Path.create(parentPath, moved.getName(), moved.getIndex(), false);                                    }                                } catch (MalformedPathException e) {                                    // should never happen actually                                    String msg = "Malformed path for item: " + state.getId();                                    log.error(msg);                                    throw new ItemStateException(msg, e);                                }                                events.add(EventState.childNodeRemoved(parent.getNodeId(),                                        parentPath,                                        n.getNodeId(),                                        oldPath.getNameElement(),                                        nodeType.getQName(),                                        mixins,                                        session));                                events.add(EventState.childNodeAdded(parent.getNodeId(),                                        parentPath,                                        n.getNodeId(),                                        newPath.getNameElement(),                                        nodeType.getQName(),                                        mixins,                                        session));                            }                        }                    }                }                // check if child nodes of modified node state have been reordered                List reordered = n.getReorderedChildNodeEntries();                NodeTypeImpl nodeType = getNodeType(n, session);                Set mixins = n.getMixinTypeNames();                if (reordered.size() > 0) {                    // create a node removed and a node added event for every                    // reorder                    for (Iterator ro = reordered.iterator(); ro.hasNext();) {                        NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) ro.next();                        QName name = child.getName();                        int index = (child.getIndex() != 1) ? child.getIndex() : 0;                        Path parentPath = getPath(n.getNodeId(), hmgr);                        Path.PathElement addedElem = Path.create(name, index).getNameElement();                        // get removed index                        NodeState overlayed = (NodeState) n.getOverlayedState();                        NodeState.ChildNodeEntry entry = overlayed.getChildNodeEntry(child.getId());                        if (entry == null) {                            throw new ItemStateException("Unable to retrieve old child index for item: " + child.getId());                        }                        int oldIndex = (entry.getIndex() != 1) ? entry.getIndex() : 0;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?