cachinghierarchymanager.java

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

JAVA
841
字号
/* * 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;import org.apache.commons.collections.map.ReferenceMap;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.NodeState;import org.apache.jackrabbit.core.state.NodeStateListener;import org.apache.jackrabbit.core.util.Dumpable;import org.apache.jackrabbit.name.MalformedPathException;import org.apache.jackrabbit.name.Path;import org.apache.jackrabbit.name.PathResolver;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.util.PathMap;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Set;import java.io.PrintStream;import javax.jcr.ItemNotFoundException;import javax.jcr.PathNotFoundException;import javax.jcr.RepositoryException;/** * Implementation of a <code>HierarchyManager</code> that caches paths of * items. */public class CachingHierarchyManager extends HierarchyManagerImpl        implements NodeStateListener, Dumpable {    /**     * Default upper limit of cached states     */    public static final int DEFAULT_UPPER_LIMIT = 10000;    /**     * Logger instance     */    private static Logger log = LoggerFactory.getLogger(CachingHierarchyManager.class);    /**     * Mapping of paths to children in the path map     */    private final PathMap pathCache = new PathMap();    /**     * Mapping of item ids to <code>LRUEntry</code> in the path map     */    private final ReferenceMap idCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.HARD);    /**     * Set of items that were moved     */    private final Set movedIds = new HashSet();    /**     * Cache monitor object     */    private final Object cacheMonitor = new Object();    /**     * Upper limit     */    private final int upperLimit;    /**     * Head of LRU     */    private LRUEntry head;    /**     * Tail of LRU     */    private LRUEntry tail;    /**     * Create a new instance of this class.     *     * @param rootNodeId   root node id     * @param provider     item state manager     * @param resolver   namespace resolver     */    public CachingHierarchyManager(NodeId rootNodeId,                                   ItemStateManager provider,                                   PathResolver resolver) {        super(rootNodeId, provider, resolver);        upperLimit = DEFAULT_UPPER_LIMIT;    }    //-------------------------------------------------< base class overrides >    /**     * {@inheritDoc}     * <p/>     * Cache the intermediate item inside our cache.     */    protected ItemId resolvePath(Path path, ItemState state, int next)            throws ItemStateException {        if (state.isNode() && !isCached(state.getId())) {            try {                Path.PathBuilder builder = new Path.PathBuilder();                Path.PathElement[] elements = path.getElements();                for (int i = 0; i < next; i++) {                    builder.addLast(elements[i]);                }                Path parentPath = builder.getPath();                cache((NodeState) state, parentPath);            } catch (MalformedPathException mpe) {                log.warn("Failed to build path of " + state.getId(), mpe);            }        }        return super.resolvePath(path, state, next);    }    /**     * {@inheritDoc}     * <p/>     * Overridden method tries to find a mapping for the intermediate item     * <code>state</code> and add its path elements to the builder currently     * being used. If no mapping is found, the item is cached instead after     * the base implementation has been invoked.     */    protected void buildPath(Path.PathBuilder builder, ItemState state)            throws ItemStateException, RepositoryException {        if (state.isNode()) {            PathMap.Element element = get(state.getId());            if (element != null) {                try {                    Path.PathElement[] elements = element.getPath().getElements();                    for (int i = elements.length - 1; i >= 0; i--) {                        builder.addFirst(elements[i]);                    }                    return;                } catch (MalformedPathException mpe) {                    String msg = "Failed to build path of " + state.getId();                    log.debug(msg);                    throw new RepositoryException(msg, mpe);                }            }        }        super.buildPath(builder, state);        if (state.isNode()) {            try {                cache((NodeState) state, builder.getPath());            } catch (MalformedPathException mpe) {                log.warn("Failed to build path of " + state.getId());            }        }    }    //-----------------------------------------------------< HierarchyManager >    /**     * {@inheritDoc}     * <p/>     * Check the path indicated inside our cache first.     */    public ItemId resolvePath(Path path) throws RepositoryException {        // Run base class shortcut and sanity checks first        if (path.denotesRoot()) {            return rootNodeId;        } else if (!path.isCanonical()) {            String msg = "path is not canonical";            log.debug(msg);            throw new RepositoryException(msg);        }        PathMap.Element element = map(path);        if (element == null) {            return super.resolvePath(path);        }        LRUEntry entry = (LRUEntry) element.get();        if (element.hasPath(path)) {            entry.touch();            return entry.getId();        }        return super.resolvePath(path, entry.getId(), element.getDepth() + 1);    }    /**     * {@inheritDoc}     * <p/>     * Overridden method simply checks whether we have an item matching the id     * and returns its path, otherwise calls base implementation.     */    public Path getPath(ItemId id)            throws ItemNotFoundException, RepositoryException {        if (id.denotesNode()) {            PathMap.Element element = get(id);            if (element != null) {                try {                    return element.getPath();                } catch (MalformedPathException mpe) {                    String msg = "Failed to build path of " + id;                    log.debug(msg);                    throw new RepositoryException(msg, mpe);                }            }        }        return super.getPath(id);    }    /**     * {@inheritDoc}     */    public QName getName(ItemId id)            throws ItemNotFoundException, RepositoryException {        if (id.denotesNode()) {            PathMap.Element element = get(id);            if (element != null) {                return element.getName();            }        }        return super.getName(id);    }    /**     * {@inheritDoc}     */    public int getDepth(ItemId id)            throws ItemNotFoundException, RepositoryException {        if (id.denotesNode()) {            PathMap.Element element = get(id);            if (element != null) {                return element.getDepth();            }        }        return super.getDepth(id);    }    /**     * {@inheritDoc}     */    public boolean isAncestor(NodeId nodeId, ItemId itemId)            throws ItemNotFoundException, RepositoryException {        if (itemId.denotesNode()) {            PathMap.Element element = get(nodeId);            if (element != null) {                PathMap.Element child = get(itemId);                if (child != null) {                    return element.isAncestorOf(child);                }            }        }        return super.isAncestor(nodeId, itemId);    }    //----------------------------------------------------< ItemStateListener >    /**     * {@inheritDoc}     */    public void stateCreated(ItemState created) {    }    /**     * {@inheritDoc}     */    public void stateModified(ItemState modified) {        if (modified.isNode()) {            nodeModified((NodeState) modified);        }    }    /**     * {@inheritDoc}     *     * Evict moved or renamed items from the cache.     */    public void nodeModified(NodeState modified) {        synchronized (cacheMonitor) {            LRUEntry entry = (LRUEntry) idCache.get(modified.getNodeId());            if (entry == null) {                // Item not cached, ignore                return;            }            PathMap.Element element = entry.getElement();            Iterator iter = element.getChildren();            while (iter.hasNext()) {                PathMap.Element child = (PathMap.Element) iter.next();                NodeState.ChildNodeEntry cne = modified.getChildNodeEntry(                        child.getName(), child.getNormalizedIndex());                if (cne == null) {                    // Item does not exist, remove                    child.remove();                    remove(child);                    return;                }                LRUEntry childEntry = (LRUEntry) child.get();                if (childEntry != null && !cne.getId().equals(childEntry.getId())) {                    // Different child item, remove                    child.remove();                    remove(child);                }            }        }    }    /**     * {@inheritDoc}     */    public void stateDestroyed(ItemState destroyed) {        remove(destroyed.getId());    }    /**     * {@inheritDoc}     */    public void stateDiscarded(ItemState discarded) {        if (discarded.isTransient() && !discarded.hasOverlayedState()                && discarded.getStatus() == ItemState.STATUS_NEW) {            // a new node has been discarded -> remove from cache            remove(discarded.getId());        } else if (provider.hasItemState(discarded.getId())) {            evict(discarded.getId());        } else {            remove(discarded.getId());        }    }    /**     * {@inheritDoc}     */    public void nodeAdded(NodeState state, QName name, int index, NodeId id) {        // Optimization: ignore notifications for nodes that are not in the cache        synchronized (cacheMonitor) {            if (idCache.containsKey(state.getNodeId())) {                try {                    Path path = Path.create(getPath(state.getNodeId()), name, index, true);                    insert(path, id);                } catch (PathNotFoundException e) {                    log.warn("Unable to get path of node " + state.getNodeId()                            + ", event ignored.");                } catch (MalformedPathException e) {                    log.warn("Unable to create path of " + id, e);                } catch (ItemNotFoundException e) {                    log.warn("Unable to find item " + state.getNodeId(), e);                } catch (RepositoryException e) {                    log.warn("Unable to get path of " + state.getNodeId(), e);                }            }        }    }    /**     * {@inheritDoc}     * <p/>     * Iterate over all cached children of this state and verify each     * child's position.     */    public void nodesReplaced(NodeState state) {        synchronized (cacheMonitor) {            LRUEntry entry = (LRUEntry) idCache.get(state.getNodeId());            if (entry != null) {                PathMap.Element element = entry.getElement();                Iterator iter = element.getChildren();                while (iter.hasNext()) {                    PathMap.Element child = (PathMap.Element) iter.next();                    LRUEntry childEntry = (LRUEntry) child.get();                    if (childEntry == null) {                        /**                         * Child has no associated UUID information: we're                         * therefore unable to determine if this child's                         * position is still accurate and have to assume                         * the worst and remove it.                         */                        child.remove(false);                        remove(child);                        continue;                    }                    NodeId childId = childEntry.getId();                    NodeState.ChildNodeEntry cne = state.getChildNodeEntry(childId);                    if (cne == null) {                        /* Child no longer in parent node state, so remove it */                        child.remove(false);                        remove(child);                        continue;                    }                    if (!cne.getName().equals(child.getName()) ||                            cne.getIndex() != child.getNormalizedIndex()) {                        /* Child still exists but at a different position */                        element.move(child.getPathElement(),                                Path.PathElement.create(cne.getName(), cne.getIndex()));                        continue;                    }                    /* At this point the child's position is still valid */                }            }        }    }

⌨️ 快捷键说明

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