📄 abstractnode.java
字号:
/* * 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.commons;import java.io.InputStream;import java.util.Calendar;import javax.jcr.Item;import javax.jcr.ItemNotFoundException;import javax.jcr.ItemVisitor;import javax.jcr.Node;import javax.jcr.PathNotFoundException;import javax.jcr.Property;import javax.jcr.PropertyIterator;import javax.jcr.RepositoryException;import javax.jcr.Session;import javax.jcr.UnsupportedRepositoryOperationException;import javax.jcr.Value;import javax.jcr.ValueFactory;import javax.jcr.lock.LockException;import javax.jcr.nodetype.NodeType;import javax.jcr.nodetype.NodeTypeManager;import javax.jcr.version.Version;import javax.jcr.version.VersionHistory;import org.apache.jackrabbit.name.QName;/** * Abstract base class for implementing the JCR {@link Node} interface. * <p> * {@link Item} methods <em>without</em> a default implementation: * <ul> * <li>{@link Item#accept(javax.jcr.ItemVisitor)}</li> * <li>{@link Item#getName()}</li> * <li>{@link Item#getParent()}</li> * <li>{@link Item#getSession()}</li> * <li>{@link Item#isModified()}</li> * <li>{@link Item#isNew()}</li> * <li>{@link Item#isSame(Item)}</li> * <li>{@link Item#refresh(boolean)}</li> * <li>{@link Item#remove()}</li> * <li>{@link Item#save()}</li> * </ul> * <p> * {@link Node} methods <em>without</em> a default implementation: * <ul> * <li>{@link Node#addMixin(String)}</li> * <li>{@link Node#addNode(String)}</li> * <li>{@link Node#addNode(String, String))}</li> * <li>{@link Node#canAddMixin(String)}</li> * <li>{@link Node#cancelMerge(Version)}</li> * <li>{@link Node#checkin()}</li> * <li>{@link Node#checkout()}</li> * <li>{@link Node#doneMerge(Version)}</li> * <li>{@link Node#getBaseVersion()}</li> * <li>{@link Node#getCorrespondingNodePath(String)}</li> * <li>{@link Node#getDefinition()}</li> * <li>{@link Node#getIndex()}</li> * <li>{@link Node#getLock()}</li> * <li>{@link Node#getNode(String)}</li> * <li>{@link Node#getNodes()}</li> * <li>{@link Node#getNodes(String)}</li> * <li>{@link Node#getPrimaryItem()}</li> * <li>{@link Node#getProperties()}</li> * <li>{@link Node#getProperties(String)}</li> * <li>{@link Node#getReferences()}</li> * <li>{@link Node#lock(boolean, boolean)}</li> * <li>{@link Node#merge(String, boolean)}</li> * <li>{@link Node#orderBefore(String, String)}</li> * <li>{@link Node#removeMixin(String)}</li> * <li>{@link Node#restore(Version, String, boolean)}</li> * <li>{@link Node#setProperty(String, Value)}</li> * <li>{@link Node#setProperty(String, Value[])}</li> * <li>{@link Node#unlock()}</li> * <li>{@link Node#update(String)}</li> * </ul> */public abstract class AbstractNode extends AbstractItem implements Node { //----------------------------------------------------------------< Item > /** * Accepts the given item visitor. * <p> * The default implementation calls {@link ItemVisitor#visit(Node)} on * the given visitor with this node as the argument. * * @param visitor item visitor * @throws RepositoryException if an error occurs */ public void accept(ItemVisitor visitor) throws RepositoryException { visitor.visit(this); } /** * Returns the path of this node. * <p> * The default implementation recursively calls this method on the * parent node and appends the name and optionally the index of this * node to construct the full path. Returns "/" if the parent node is * not available (i.e. this is the root node). * * @return node path * @throws RepositoryException if an error occurs */ public String getPath() throws RepositoryException { try { StringBuffer buffer = new StringBuffer(getParent().getPath()); if (buffer.length() > 1) { buffer.append('/'); } buffer.append(getName()); int index = getIndex(); if (index != 1) { buffer.append('['); buffer.append(index); buffer.append(']'); } return buffer.toString(); } catch (ItemNotFoundException e) { return "/"; } } /** * Returns <code>true</code>. * * @return <code>true</code> */ public boolean isNode() { return true; } //----------------------------------------------------------------< Node > /** * Returns the declared mixin node types of this node. * <p> * The default implementation uses the values of the * <code>jcr:mixinTypes</code> property to look up the mixin node types * from the {@link NodeTypeManager} of the current workspace. * * @return mixin node types * @throws RepositoryException if an error occurs */ public NodeType[] getMixinNodeTypes() throws RepositoryException { try { NodeTypeManager manager = getSession().getWorkspace().getNodeTypeManager(); Property property = getProperty(getName(QName.JCR_MIXINTYPES)); Value[] values = property.getValues(); NodeType[] types = new NodeType[values.length]; for (int i = 0; i < values.length; i++) { types[i] = manager.getNodeType(values[i].getString()); } return types; } catch (PathNotFoundException e) { // jcr:mixinTypes does not exist, i.e. no mixin types on this node return new NodeType[0]; } } /** * Returns the primary node type of this node. * <p> * The default implementation uses the value of the * <code>jcr:primaryType</code> property to look up the primary * node type from the {@link NodeTypeManager} of the current workspace. * * @return primary node type * @throws RepositoryException if an error occurs */ public NodeType getPrimaryNodeType() throws RepositoryException { NodeTypeManager manager = getSession().getWorkspace().getNodeTypeManager(); Property property = getProperty(getName(QName.JCR_PRIMARYTYPE)); return manager.getNodeType(property.getString()); } /** * Returns the property at the given relative path from this node. * <p> * The default implementation looks up the parent node of the given * relative path and iterates through the properties of that node to * find and return the identified property. * * @param relPath relative path of the property * @return property * @throws PathNotFoundException if the property is not found * @throws RepositoryException if an error occurs */ public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException { // Corner case, remove any "/." self references at the end of the path while (relPath.endsWith("/.")) { relPath = relPath.substring(0, relPath.length() - 2); } // Find the parent node of the identified property Node node = this; int slash = relPath.lastIndexOf('/'); if (slash == 0) { node = getSession().getRootNode(); relPath = relPath.substring(1); } else if (slash > 0) { node = getNode(relPath.substring(0, slash)); relPath = relPath.substring(slash + 1); } // Look for the named property. Must iterate and re-check for the name // since the client could have used an invalid path like "./a|b". PropertyIterator properties = node.getProperties(relPath); while (properties.hasNext()) { Property property = (Property) properties.next(); if (relPath.equals(property.getName())) { return property; } } throw new PathNotFoundException("Property not found: " + relPath); } /** * Returns the UUID of this node. * <p> * The default implementation checks if this node is referenceable (i.e. of * type <code>mix:referenceable</code>) and returns the contents of the * <code>jcr:uuid</code> property if it is. * * @return node UUID * @throws UnsupportedRepositoryOperationException * if this node is not referenceable * @throws RepositoryException if an error occurs */ public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException { if (isNodeType(getName(QName.MIX_REFERENCEABLE))) { return getProperty(getName(QName.JCR_UUID)).getString(); } else { throw new UnsupportedRepositoryOperationException( "This node is not referenceable: " + getPath()); } } /** * Returns the version history of this node. * <p> * The default implementation returns the containing version history of * the base version of this node. * * @return version history * @throws RepositoryException if an error occurs */ public VersionHistory getVersionHistory() throws RepositoryException { return getBaseVersion().getContainingHistory(); } /** * Checks whether a node at the given relative path exists. * <p> * The default implementation looks up the node using * {@link Node#getNode(String)} and returns <code>true</code> if * a {@link PathNotFoundException} is not thrown. * * @param relPath relative path * @return <code>true</code> if a node exists at the given path, * <code>false</code> otherwise * @throws RepositoryException if an error occurs */ public boolean hasNode(String relPath) throws RepositoryException { try { getNode(relPath); return true; } catch (PathNotFoundException e) { return false; } } /** * Checks if this node has one or more properties. * <p> * The default implementation calls {@link Node#getNodes()} and returns * <code>true</code> iff returned iterator has at least one element. * * @return <code>true</code> if this node has child nodes, * <code>false</code> otherwise * @throws RepositoryException if an error occurs */ public boolean hasNodes() throws RepositoryException { return getNodes().hasNext(); } /** * Checks if this node has one or more properties. * <p> * The default implementation calls {@link Node#getProperties()} and * returns <code>true</code> iff returned iterator has at least one element. * <p> * Note that in normal circumstances (i.e. no weird access controls) this * method will always return <code>true</code> since all nodes always have * at least the <code>jcr:primaryType</code> property. * * @return <code>true</code> if this node has properties, * <code>false</code> otherwise * @throws RepositoryException if an error occurs */ public boolean hasProperties() throws RepositoryException { return getProperties().hasNext(); } /** * Checks whether a property at the given relative path exists. * <p> * The default implementation looks up the property using * {@link Node#getProperty(String)} and returns <code>true</code> if * a {@link PathNotFoundException} is not thrown. * * @param relPath relative path * @return <code>true</code> if a property exists at the given path, * <code>false</code> otherwise * @throws RepositoryException if an error occurs */ public boolean hasProperty(String relPath) throws RepositoryException { try { getProperty(relPath); return true; } catch (PathNotFoundException e) { return false; } } /** * Checks if this node holds a lock. * <p> * The default implementation calls {@link Node#getLock()} and returns * <code>true</code> iff the holding node of the lock is the same as this * node. * * @return <code>true</code> if this node holds a lock, * <code>false</code> otherwise * @throws RepositoryException if an error occurs */ public boolean holdsLock() throws RepositoryException { try { return isSame(getLock().getNode()); } catch (LockException e) { return false; } } /** * Checks whether this node is checked out. * <p> * The default implementation checks the <code>jcr:isCheckedOut</code> * property if this node is versionable, and recursively calls this method * on the parent node if this node is not versionable. A non-versionable * root node always returns <code>true</code> from this method. * * @return <code>true</code> if this node is checked out, * <code>false</code> otherwise * @throws RepositoryException if an error occurs */ public boolean isCheckedOut() throws RepositoryException { if (isNodeType(getName(QName.MIX_VERSIONABLE))) { // This node is versionable, check the jcr:isCheckedOut property return getProperty(getName(QName.JCR_ISCHECKEDOUT)).getBoolean(); } else { try { // This node is not versionable, is the parent checked out? return getParent().isCheckedOut(); } catch (ItemNotFoundException e) { // This node is the root node, always checked out
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -