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 + -
显示快捷键?