Java tutorial
/** * * Magnolia and its source-code is licensed under the LGPL. * You may copy, adapt, and redistribute this file for commercial or non-commercial use. * When copying, adapting, or redistributing this document in keeping with the guidelines above, * you are required to provide proper attribution to obinary. * If you reproduce or distribute the document without making any substantive modifications to its content, * please use the following attribution line: * * Copyright 1993-2006 obinary Ltd. (http://www.obinary.com) All rights reserved. * */ package info.magnolia.cms.core; import info.magnolia.cms.core.version.ContentVersion; import info.magnolia.cms.core.version.VersionManager; import info.magnolia.cms.security.AccessDeniedException; import info.magnolia.cms.security.AccessManager; import info.magnolia.cms.security.Authenticator; import info.magnolia.cms.security.Permission; import info.magnolia.cms.util.Rule; import info.magnolia.context.MgnlContext; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.TreeSet; import javax.jcr.Item; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.Value; import javax.jcr.Workspace; import javax.jcr.lock.Lock; import javax.jcr.lock.LockException; import javax.jcr.nodetype.NodeType; import javax.jcr.version.Version; import javax.jcr.version.VersionException; import javax.jcr.version.VersionHistory; import javax.jcr.version.VersionIterator; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Sameer Charles * @version $Revision:2719 $ ($Author:scharles $) */ public class Content extends ContentHandler implements Cloneable { /** * Logger. */ private static Logger log = LoggerFactory.getLogger(Content.class); /** * Wrapped jcr node. */ protected Node node; /** * Path for the jcr node. */ private String path; /** * root node. */ private Node rootNode; /** * node metadata. */ private MetaData metaData; /** * Empty constructor. Should NEVER be used for standard use, test only. */ protected Content() { } /** * Constructor to get existing node. * @param rootNode node to start with * @param path absolute (primary) path to this <code>Node</code> * @param manager AccessManager instance * @throws PathNotFoundException if the node at <code>path</code> does not exist * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs */ public Content(Node rootNode, String path, AccessManager manager) throws PathNotFoundException, RepositoryException, AccessDeniedException { Access.isGranted(manager, Path.getAbsolutePath(rootNode.getPath(), path), Permission.READ); this.setPath(path); this.setRootNode(rootNode); this.setNode(this.rootNode.getNode(this.path)); this.setAccessManager(manager); } /** * Constructor to get existing node. * @param elem initialized node object * @param manager AccessManager instance * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs */ public Content(Item elem, AccessManager manager) throws RepositoryException, AccessDeniedException { Access.isGranted(manager, Path.getAbsolutePath(elem.getPath()), Permission.READ); this.setNode((Node) elem); this.setPath(this.getHandle()); this.setAccessManager(manager); } /** * creates contentNode of type <b>contentType </b> contentType must be defined in item type definition of magnolia * as well as JCR implementation * @param rootNode node to start with * @param path absolute (primary) path to this <code>Node</code> * @param contentType JCR node type as configured * @param manager AccessManager instance * @throws PathNotFoundException if the node at <code>path</code> does not exist * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public Content(Node rootNode, String path, String contentType, AccessManager manager) throws PathNotFoundException, RepositoryException, AccessDeniedException { Access.isGranted(manager, Path.getAbsolutePath(rootNode.getPath(), path), Permission.WRITE); this.setPath(path); this.setRootNode(rootNode); this.node = this.rootNode.addNode(this.path, contentType); this.setAccessManager(manager); this.addMixin(ItemType.MIX_VERSIONABLE); } /** * bit by bit copy of the current object. Warning: this doesn't clone wrapped jcr nodes. * @return Object cloned object */ public Object clone() { // don't add throws CloneNotSupportedException! the super class ContentHandler doesn't throw // it anymore, so it will not compile return super.clone(); } /** * @param node */ protected void setNode(Node node) { this.node = node; } /** * @param node */ protected void setRootNode(Node node) { this.rootNode = node; } /** * @param path */ protected void setPath(String path) { this.path = path; } /** * get ContentNode node of the current node with the specified name * @param path of the node acting as <code>ContentNode</code> * @return ContentNode * @throws PathNotFoundException if the node at <code>path</code> does not exist * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @deprecated use getContent(String name) instead */ public Content getContentNode(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException { return new Content(this.node, path, this.accessManager); } /** * create ContentNode node under the current node with the specified name * @param name of the node to be created as <code>ContentNode</code> * @return newly created <node>ContentNode </node> * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @deprecated use createContent(String name, String contentType) instead */ public Content createContentNode(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException { return this.createContent(name, ItemType.CONTENTNODE); } /** * get Content node of the current node with the specified name * @param name of the node acting as <code>Content</code> * @return <node>Content </node> * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public Content getContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException { return (new Content(this.node, name, this.accessManager)); } /** * Like getContent but creates the node if not existing. * @param name * @param create true if the node is created * @param contentType the type of the created node * @return * @throws AccessDeniedException * @throws RepositoryException * @deprecated use the ContentUtil instead */ public Content getContent(String name, boolean create, ItemType contentType) throws AccessDeniedException, RepositoryException { Content node; try { node = this.getContent(name); } catch (PathNotFoundException e) { if (create) { node = this.createContent(name, contentType); } else { throw e; } } return node; } /** * create Content node under the current node with the specified name * @param name of the node to be created as <code>Content</code> * @return newly created <node>Content </node> * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public Content createContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException { return this.createContent(name, ItemType.CONTENT); } /** * create Content node under the current node with the specified name * @param name of the node to be created as <code>Content</code> * @param contentType JCR node type as configured * @return newly created <node>Content </node> * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public Content createContent(String name, String contentType) throws PathNotFoundException, RepositoryException, AccessDeniedException { Content content = (new Content(this.node, name, contentType, this.accessManager)); MetaData metaData = content.getMetaData(); metaData.setCreationDate(); return content; } /** * Create Content node under the current node with the specified name. * @param name of the node to be created as <code>Content</code> * @param contentType ItemType * @return newly created <node>Content </node> * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public Content createContent(String name, ItemType contentType) throws PathNotFoundException, RepositoryException, AccessDeniedException { Content content = (new Content(this.node, name, contentType.getSystemName(), this.accessManager)); MetaData metaData = content.getMetaData(); metaData.setCreationDate(); return content; } /** * @return String, template name */ public String getTemplate() { return this.getMetaData().getTemplate(); } /** * @return String, title */ public String getTitle() { return this.getNodeData("title").getString(); //$NON-NLS-1$ } /** * get meta data of the current node * @return MetaData meta information of the content <code>Node</code> */ public MetaData getMetaData() { if (this.metaData == null) { this.metaData = new MetaData(this.node, this.accessManager); } return this.metaData; } /** * get top level NodeData * @return NodeData requested <code>NodeData</code> object */ public NodeData getNodeData(String name) { try { return (new NodeData(this.node, name, this.accessManager)); } catch (PathNotFoundException e) { if (log.isDebugEnabled()) { String nodepath = null; try { nodepath = this.node.getPath(); } catch (RepositoryException e1) { // ignore, debug only } if (log.isDebugEnabled()) { log.debug("Path not found for property [" + name + "] in node " + nodepath); //$NON-NLS-1$ //$NON-NLS-2$ } } return (new NodeData()); } catch (RepositoryException re) { String nodepath = null; try { nodepath = this.node.getPath(); } catch (RepositoryException e1) { // ignore, debug only } log.warn("Repository exception while trying to read property [" + name + "] for node " + nodepath, re); //$NON-NLS-1$ //$NON-NLS-2$ return (new NodeData()); } } /** * @param name * @param create * @deprecated use NodeDataUtil.getOrCreate(name) */ public NodeData getNodeData(String name, boolean create) { try { return (new NodeData(this.node, name, this.accessManager)); } catch (PathNotFoundException e) { if (create) { try { return this.createNodeData(name); } catch (Exception e1) { log.error("can't create property [" + name + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } } if (log.isDebugEnabled()) { String nodepath = null; try { nodepath = this.node.getPath(); } catch (RepositoryException e1) { // ignore, debug only } if (log.isDebugEnabled()) { log.debug("Path not found for property [" + name + "] in node " + nodepath); //$NON-NLS-1$ //$NON-NLS-2$ } } return (new NodeData()); } catch (RepositoryException re) { String nodepath = null; try { nodepath = this.node.getPath(); } catch (RepositoryException e1) { // ignore, debug only } log.warn("Repository exception while trying to read property [" + name + "] for node " + nodepath, re); //$NON-NLS-1$ //$NON-NLS-2$ return (new NodeData()); } } /** * get node name * @return String name of the current <code>Node</code> */ public String getName() { try { return this.node.getName(); } catch (RepositoryException e) { log.error(e.getMessage(), e); } return StringUtils.EMPTY; } /** * create top level NodeData object * @param name to be created * @return NodeData requested <code>NodeData</code> object * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public NodeData createNodeData(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException { return (new NodeData(this.node, name, PropertyType.STRING, true, this.accessManager)); } /** * create top level NodeData object * @param name to be created * @param type propertyType * @return NodeData requested <code>NodeData</code> object * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public NodeData createNodeData(String name, int type) throws PathNotFoundException, RepositoryException, AccessDeniedException { return (new NodeData(this.node, name, type, true, this.accessManager)); } /** * Create NodeData with the given value and type. * @param name to be created * @param value to be set initially * @return NodeData requested <code>NodeData</code> object * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public NodeData createNodeData(String name, Value value) throws PathNotFoundException, RepositoryException, AccessDeniedException { return (new NodeData(this.node, name, value, this.accessManager)); } /** * Set NodeData value. * @param name to be created * @param value to be set initially * @return NodeData requested <code>NodeData</code> object * @throws PathNotFoundException * @throws RepositoryException if an error occurs * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation */ public NodeData setNodeData(String name, Value value) throws PathNotFoundException, RepositoryException, AccessDeniedException { NodeData nodeData; try { nodeData = new NodeData(this.node, name, this.accessManager); nodeData.setValue(value); } catch (PathNotFoundException e) { nodeData = new NodeData(this.node, name, value, this.accessManager); } return nodeData; } /** * delete NodeData with the specified name * @throws PathNotFoundException * @throws RepositoryException if an error occurs */ public void deleteNodeData(String name) throws PathNotFoundException, RepositoryException { if (this.node.hasNode(name)) { this.node.getNode(name).remove(); } else { this.node.getProperty(name).remove(); } } /** * you could call this method anytime to update working page properties - Modification date & Author ID * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs */ public void updateMetaData() throws RepositoryException, AccessDeniedException { MetaData md = this.getMetaData(); md.setModificationDate(); md.setAuthorId(MgnlContext.getUser().getName()); } /** * you could call this method anytime to update working page properties - Modification date & Author ID * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs * @deprecated use the the method without a request object passed */ public void updateMetaData(HttpServletRequest request) throws RepositoryException, AccessDeniedException { MetaData md = this.getMetaData(); md.setModificationDate(); md.setAuthorId(Authenticator.getUserId(request)); } /** * Get a collection containing child nodes which satisfies the given filter * @param filter * @return Collection of content objects */ public Collection getChildren(ContentFilter filter) { return getChildren(filter, null); } /** * Get a collection containing child nodes which satisfies the given filter. The returned collection is ordered * according to the passed in criteria. * @param filter filter for the child nodes * @param orderCriteria ordering for the selected child nodes; if <tt>null</tt> than no particular order of the * child nodes * @return Collection of content objects */ public Collection getChildren(ContentFilter filter, Comparator orderCriteria) { Collection children; if (orderCriteria == null) { children = new ArrayList(); } else { children = new TreeSet(orderCriteria); } try { NodeIterator nodeIterator = this.node.getNodes(); while (nodeIterator.hasNext()) { Node subNode = (Node) nodeIterator.next(); try { Content content = new Content(subNode, this.accessManager); if (filter.accept(content)) { children.add(content); } } catch (PathNotFoundException e) { log.error("Exception caught", e); } catch (AccessDeniedException e) { // ignore, simply wont add content in a list } } } catch (RepositoryException re) { log.error("Exception caught", re); } return children; } /** * gets a Collection containing all child nodes of the same NodeType as "this" object. * @return Collection of content objects */ public Collection getChildren() { String type = null; try { type = this.getNodeTypeName(); } catch (RepositoryException re) { log.error(re.getMessage()); log.debug(re.getMessage(), re); } // fix all getChildren calls from the root node if ("rep:root".equalsIgnoreCase(type)) { //$NON-NLS-1$ type = ItemType.CONTENT.getSystemName(); } // -------------------------------------------------- return this.getChildren(type); } /** * @param contentType * @param sortCriteria * @return Collection of content nodes * @deprecated use JCR ordering */ public Collection getChildren(String contentType, int sortCriteria) { return this.getChildren(contentType); } /** * @param contentType * @param sortCriteria * @return Collection of content nodes * @deprecated use JCR ordering */ public Collection getChildren(ItemType contentType, int sortCriteria) { return this.getChildren(contentType); } /** * Get collection of specified content type * @param contentType JCR node type as configured * @return Collection of content nodes */ public Collection getChildren(String contentType) { return this.getChildren(contentType, "*"); //$NON-NLS-1$ } /** * Get collection of specified content type * @param contentType ItemType * @return Collection of content nodes */ public Collection getChildren(ItemType contentType) { return this.getChildren(contentType != null ? contentType.getSystemName() : (String) null); } /** * Get collection of specified content type. * @param contentType JCR node type as configured * @param namePattern * @return Collection of content nodes */ public Collection getChildren(String contentType, String namePattern) { Collection children = new ArrayList(); try { children = this.getChildContent(contentType, namePattern); } catch (RepositoryException e) { log.error(e.getMessage(), e); } return children; } /** * Returns the first child with the given name, any node type * @param namePattern child node name * @return first found node with the given name or <code>null</code> if not found */ public Content getChildByName(String namePattern) { Collection children = null; try { children = getChildContent(null, namePattern); } catch (RepositoryException e) { log.error(e.getMessage(), e); } if (children != null && !children.isEmpty()) { return (Content) children.iterator().next(); } return null; } /** * @param contentType JCR node type as configured, <code>null</code> means no filter * @param namePattern, <code>null</code> means no filter * @return COllection of <code>Content</code> objects * @throws RepositoryException if an error occurs */ private Collection getChildContent(String contentType, String namePattern) throws RepositoryException { Collection children = new ArrayList(); NodeIterator nodeIterator = namePattern != null ? this.node.getNodes(namePattern) : this.node.getNodes(); while (nodeIterator.hasNext()) { Node subNode = (Node) nodeIterator.next(); try { if (contentType == null || this.isNodeType(subNode, contentType)) { children.add(new Content(subNode, this.accessManager)); } } catch (PathNotFoundException e) { log.error("Exception caught", e); } catch (AccessDeniedException e) { // ignore, simply wont add content in a list } } return children; } /** * Gets all properties bind in NodeData object excluding JCR system properties */ public Collection getNodeDataCollection() { Collection children = new ArrayList(); try { PropertyIterator propertyIterator = this.node.getProperties(); while (propertyIterator.hasNext()) { Property property = (Property) propertyIterator.next(); try { if (!property.getName().startsWith("jcr:") && !property.getName().startsWith("mgnl:")) { //$NON-NLS-1$ //$NON-NLS-2$ children.add(new NodeData(property, this.accessManager)); } } catch (PathNotFoundException e) { log.error("Exception caught", e); } catch (AccessDeniedException e) { // ignore, simply wont add content in a list } } // add nt:resource nodes children.addAll(this.getBinaryProperties("*")); } catch (RepositoryException re) { log.error("Exception caught", re); } return children; } /** * Gets all properties bind in NodeData object which qualify the given namePattern * @param namePattern */ public Collection getNodeDataCollection(String namePattern) { Collection children = new ArrayList(); try { PropertyIterator propertyIterator = this.node.getProperties(namePattern); if (propertyIterator == null) { return children; } while (propertyIterator.hasNext()) { Property property = (Property) propertyIterator.next(); try { children.add(new NodeData(property, this.accessManager)); } catch (PathNotFoundException e) { log.error("Exception caught", e); } catch (AccessDeniedException e) { // ignore, simply wont add content in a list } } // add nt:resource nodes children.addAll(this.getBinaryProperties(namePattern)); } catch (RepositoryException re) { log.error("Exception caught", re); } return children; } /** * @param namePattern * @return nodeData collection * @throws RepositoryException if an error occurs */ private Collection getBinaryProperties(String namePattern) throws RepositoryException { Collection children = new ArrayList(); NodeIterator nodeIterator = this.node.getNodes(namePattern); while (nodeIterator.hasNext()) { Node subNode = (Node) nodeIterator.next(); try { if (this.isNodeType(subNode, ItemType.NT_RESOURCE)) { children.add(new NodeData(subNode, this.accessManager)); } } catch (PathNotFoundException e) { log.error(e.getMessage(), e); } catch (AccessDeniedException e) { // ignore, simply wont add content in a list } } return children; } /** * @return Boolean, if sub node(s) exists */ public boolean hasChildren() { return (this.getChildren().size() > 0); } /** * @param contentType JCR node type as configured * @return Boolean, if sub <code>collectionType</code> exists */ public boolean hasChildren(String contentType) { return (this.getChildren(contentType).size() > 0); } /** * @param name * @throws RepositoryException if an error occurs */ public boolean hasContent(String name) throws RepositoryException { return this.node.hasNode(name); } /** * @param name * @throws RepositoryException if an error occurs */ public boolean hasNodeData(String name) throws RepositoryException { return this.node.hasProperty(name); } /** * get a handle representing path relative to the content repository * @return String representing path (handle) of the content */ public String getHandle() { try { return this.node.getPath(); } catch (RepositoryException e) { log.error("Failed to get handle: " + e.getMessage(), e); //$NON-NLS-1$ return StringUtils.EMPTY; } } /** * get parent content object * @return Content representing parent node * @throws javax.jcr.PathNotFoundException * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs */ public Content getParent() throws PathNotFoundException, RepositoryException, AccessDeniedException { return (new Content(this.node.getParent(), this.accessManager)); } /** * get absolute parent object starting from the root node * @param digree level at which the requested node exist, relative to the ROOT node * @return Content representing parent node * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs */ public Content getAncestor(int digree) throws PathNotFoundException, RepositoryException, AccessDeniedException { if (digree > this.getLevel()) { throw new PathNotFoundException(); } return (new Content(this.node.getAncestor(digree), this.accessManager)); } /** * Convenience method for taglib * @return Content representing node on level 0 * @throws RepositoryException if an error occurs */ public Collection getAncestors() throws PathNotFoundException, RepositoryException { List allAncestors = new ArrayList(); int level = this.getLevel(); while (level != 0) { try { allAncestors.add(new Content(this.node.getAncestor(--level), this.accessManager)); } catch (AccessDeniedException e) { // valid } } return allAncestors; } /** * get node level from the ROOT node : FIXME implement getDepth in javax.jcr * @return level at which current node exist, relative to the ROOT node * @throws javax.jcr.PathNotFoundException * @throws RepositoryException if an error occurs */ public int getLevel() throws PathNotFoundException, RepositoryException { return this.node.getPath().split("/").length - 1; //$NON-NLS-1$ } /** * move current node to the specified location above the named <code>beforename</code> * @param srcName where current node has to be moved * @param beforeName name of the node before the current node has to be placed * @throws RepositoryException if an error occurs */ public void orderBefore(String srcName, String beforeName) throws RepositoryException { this.node.orderBefore(srcName, beforeName); } /** * This method returns the index of this node within the ordered set of its same-name sibling nodes. This index is * the one used to address same-name siblings using the square-bracket notation, e.g., /a[3]/b[4]. Note that the * index always starts at 1 (not 0), for compatibility with XPath. As a result, for nodes that do not have * same-name-siblings, this method will always return 1. * @return The index of this node within the ordered set of its same-name sibling nodes. * @throws RepositoryException if an error occurs */ public int getIndex() throws RepositoryException { return this.node.getIndex(); } /** * utility method to get Node object used to create current content object * @return Node */ public Node getJCRNode() { return this.node; } /** * evaluate primary node type of the associated Node of this object * @param type */ public boolean isNodeType(String type) { try { return this.getNodeTypeName().equalsIgnoreCase(type); } catch (RepositoryException re) { log.error(re.getMessage()); log.debug(re.getMessage(), re); } return false; } /** * private Helper method to evaluate primary node type of the given node * @param node * @param type */ private boolean isNodeType(Node node, String type) { try { return node.getProperty(ItemType.JCR_PRIMARY_TYPE).getString().equalsIgnoreCase(type); } catch (RepositoryException re) { log.error(re.getMessage()); log.debug(re.getMessage(), re); } return false; } /** * returns primary node type definition of the associated Node of this object * @throws RepositoryException if an error occurs */ public NodeType getNodeType() throws RepositoryException { return this.node.getPrimaryNodeType(); } /** * returns primary node type name of the associated Node of this object * @throws RepositoryException if an error occurs */ public String getNodeTypeName() throws RepositoryException { return this.node.getProperty(ItemType.JCR_PRIMARY_TYPE).getString(); } /** * Get the magnolia ItemType. * @return the type * @throws RepositoryException */ public ItemType getItemType() throws RepositoryException { return new ItemType(getNodeTypeName()); } /** * Restores this node to the state defined by the version with the specified versionName. * @param versionName * @param removeExisting * @throws VersionException if the specified <code>versionName</code> does not exist in this node's version * history * @throws RepositoryException if an error occurs */ public void restore(String versionName, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException { Access.isGranted(this.getAccessManager(), this.getHandle(), Permission.WRITE); Version version = this.getVersionHistory().getVersion(versionName); this.restore(version, removeExisting); } /** * Restores this node to the state defined by the specified version. * @param version * @param removeExisting * @throws VersionException if the specified <code>version</code> is not part of this node's version history * @throws RepositoryException if an error occurs */ public void restore(Version version, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException { Access.isGranted(this.getAccessManager(), this.getHandle(), Permission.WRITE); VersionManager.getInstance().restore(this, version, removeExisting); } /** * Restores the specified version to relPath, relative to this node. * @param version * @param relPath * @param removeExisting * @throws VersionException if the specified <code>version</code> is not part of this node's version history * @throws RepositoryException if an error occurs */ public void restore(Version version, String relPath, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException { throw new UnsupportedRepositoryOperationException("Not implemented in 3.0 Beta"); } /** * Restores this node to the state recorded in the version specified by versionLabel. * @param versionLabel * @param removeExisting * @throws VersionException if the specified <code>versionLabel</code> does not exist in this node's version * history * @throws RepositoryException if an error occurs */ public void restoreByLabel(String versionLabel, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException { this.node.restoreByLabel(versionLabel, removeExisting); throw new UnsupportedRepositoryOperationException("Not implemented in 3.0 Beta"); } /** * add version leaving the node checked out * @throws UnsupportedRepositoryOperationException * @throws RepositoryException if an error occurs */ public Version addVersion() throws UnsupportedRepositoryOperationException, RepositoryException { return VersionManager.getInstance().addVersion(this); } /** * add version leaving the node checked out * @param rule to be used to collect content * @throws UnsupportedRepositoryOperationException * @throws RepositoryException if an error occurs * @see info.magnolia.cms.util.Rule */ public Version addVersion(Rule rule) throws UnsupportedRepositoryOperationException, RepositoryException { return VersionManager.getInstance().addVersion(this, rule); } /** * Returns true if this node is either * <ul> * <li/>versionable and currently checked-out, <li/>non-versionable and its nearest versionable ancestor is * checked-out or <li/>non-versionable and it has no versionable ancestor. * </ul> * Returns false if this node is either * <ul> * <li/>versionable and currently checked-in or <li/>non-versionable and its nearest versionable ancestor is * checked-in. * </ul> * @return true if the node is checked out * @throws RepositoryException */ protected boolean isCheckedOut() throws RepositoryException { return this.node.isCheckedOut(); } /** * Returns <code>true</code> if this <code>Item</code> has been saved but has subsequently been modified through * the current session and therefore the state of this item as recorded in the session differs from the state of * this item as saved. Within a transaction, <code>isModified</code> on an <code>Item</code> may return * <code>false</code> (because the <code>Item</code> has been saved since the modification) even if the * modification in question is not in persistent storage (because the transaction has not yet been committed). <p/> * Note that in level 1 (that is, read-only) implementations, this method will always return <code>false</code>. * @return <code>true</code> if this item is modified; <code>false</code> otherwise. */ public boolean isModified() { return this.node.isModified(); } /** * @return version history * @throws RepositoryException if an error occurs */ public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException, RepositoryException { return VersionManager.getInstance().getVersionHistory(this); } /** * @return Version iterator retreived from version history * @throws RepositoryException if an error occurs */ public VersionIterator getAllVersions() throws UnsupportedRepositoryOperationException, RepositoryException { return VersionManager.getInstance().getAllVersions(this); } /** * get the current base version of this node * @return base ContentVersion * @throws UnsupportedRepositoryOperationException * @throws RepositoryException */ public ContentVersion getBaseVersion() throws UnsupportedRepositoryOperationException, RepositoryException { return new ContentVersion(VersionManager.getInstance().getBaseVersion(this), this); } /** * get content view over the jcr version object * @param version * @return version object wrapped in ContentVersion * @see ContentVersion */ public ContentVersion getVersionedContent(Version version) throws RepositoryException { return new ContentVersion(version, this); } /** * get content view over the jcr version object * @param versionName * @return version object wrapped in ContentVersion * @see ContentVersion */ public ContentVersion getVersionedContent(String versionName) throws RepositoryException { return new ContentVersion(VersionManager.getInstance().getVersion(this, versionName), this); } /** * removes all versions of this node and associated version graph * @throws AccessDeniedException If not allowed to do write operations on this node * @throws RepositoryException if unable to remove versions from version store * */ public void removeVersionHistory() throws AccessDeniedException, RepositoryException { Access.isGranted(this.accessManager, Path.getAbsolutePath(node.getPath()), Permission.WRITE); VersionManager.getInstance().removeVersionHistory(this.node.getUUID()); } /** * Persists all changes to the repository if validation succeds * @throws RepositoryException if an error occurs */ public void save() throws RepositoryException { this.node.getSession().save(); } /** * checks for the allowed access rights * @param permissions as defined in javax.jcr.Permission * @return true is the current user has specified access on this node. */ public boolean isGranted(long permissions) { try { Access.isGranted(this.accessManager, Path.getAbsolutePath(node.getPath()), permissions); return true; } catch (RepositoryException re) { if (log.isDebugEnabled()) log.debug(this.getHandle() + " says: no access"); //$NON-NLS-1$ } return false; } /** * Remove this path * @throws RepositoryException if an error occurs */ public void delete() throws RepositoryException { Access.isGranted(this.accessManager, Path.getAbsolutePath(this.node.getPath()), Permission.REMOVE); this.node.remove(); } /** * Remove specified path * @throws RepositoryException if an error occurs */ public void delete(String path) throws RepositoryException { Access.isGranted(this.accessManager, Path.getAbsolutePath(this.node.getPath(), path), Permission.REMOVE); if (this.isNodeData(path)) { this.getNodeData(path).delete(); } else { this.node.getNode(path).remove(); } } /** * checks if the requested resource is an NodeData (Property) * @param path of the requested NodeData * @return boolean true is the requested content is an NodeData * @throws AccessDeniedException * @throws AccessDeniedException if the current session does not have sufficient access rights to complete the * operation * @throws RepositoryException if an error occurs */ public boolean isNodeData(String path) throws AccessDeniedException, RepositoryException { Access.isGranted(this.accessManager, Path.getAbsolutePath(this.node.getPath(), path), Permission.READ); boolean result = false; try { result = this.node.hasProperty(path); if (!result) { // check if its a nt:resource result = this.node.hasProperty(path + "/" + ItemType.JCR_DATA); } } catch (RepositoryException e) { if (log.isDebugEnabled()) log.debug("isNodeData(): " + e.getMessage()); //$NON-NLS-1$ } return result; } /** * If keepChanges is false, this method discards all pending changes recorded in this session. * @throws RepositoryException if an error occurs * @see javax.jcr.Node#refresh(boolean) */ public void refresh(boolean keepChanges) throws RepositoryException { this.node.refresh(keepChanges); } /** * UUID of the node refrenced by this object * @return uuid */ public String getUUID() { try { return this.node.getUUID(); } catch (UnsupportedOperationException e) { log.error(e.getMessage()); } catch (RepositoryException re) { log.error("Exception caught", re); } return StringUtils.EMPTY; } /** * add specified mixin type if allowed * @param type mixin type to be added * @throws RepositoryException if an error occurs */ public void addMixin(String type) throws RepositoryException { Access.isGranted(this.accessManager, Path.getAbsolutePath(this.node.getPath()), Permission.SET); if (this.node.canAddMixin(type)) { this.node.addMixin(type); } else { log.error("Node - " + this.node.getPath() + " does not allow mixin type - " + type); //$NON-NLS-1$ //$NON-NLS-2$ } } /** * Removes the specified mixin node type from this node. Also removes mixinName from this node's jcr:mixinTypes * property. <b>The mixin node type removal takes effect on save</b>. * @param type , mixin type to be removed * @throws RepositoryException if an error occurs */ public void removeMixin(String type) throws RepositoryException { Access.isGranted(this.accessManager, Path.getAbsolutePath(this.node.getPath()), Permission.SET); this.node.removeMixin(type); } /** * Returns an array of NodeType objects representing the mixin node types assigned to this node. This includes only * those mixin types explicitly assigned to this node, and therefore listed in the property jcr:mixinTypes. It does * not include mixin types inherited through the additon of supertypes to the primary type hierarchy. * @return an array of mixin NodeType objects. * @throws RepositoryException if an error occurs */ public NodeType[] getMixinNodeTypes() throws RepositoryException { return this.node.getMixinNodeTypes(); } /** * places a lock on this object * @param isDeep if true this lock will apply to this node and all its descendants; if false, it applies only to * this node. * @param isSessionScoped if true, this lock expires with the current session; if false it expires when explicitly * or automatically unlocked for some other reason. * @return A Lock object containing a lock token. * @throws LockException if this node is already locked or <code>isDeep</code> is true and a descendant node of * this node already holds a lock. * @throws RepositoryException if an error occurs * @see javax.jcr.Node#lock(boolean, boolean) */ public Lock lock(boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException { return this.node.lock(isDeep, isSessionScoped); } /** * places a lock on this object * @param isDeep if true this lock will apply to this node and all its descendants; if false, it applies only to * this node. * @param isSessionScoped if true, this lock expires with the current session; if false it expires when explicitly * or automatically unlocked for some other reason. * @param yieldFor number of milliseconds for which this method will try to get a lock * @return A Lock object containing a lock token. * @throws LockException if this node is already locked or <code>isDeep</code> is true and a descendant node of * this node already holds a lock. * @throws RepositoryException if an error occurs * @see javax.jcr.Node#lock(boolean, boolean) */ public Lock lock(boolean isDeep, boolean isSessionScoped, long yieldFor) throws LockException, RepositoryException { long finalTime = System.currentTimeMillis() + yieldFor; LockException lockException = null; while (System.currentTimeMillis() <= finalTime) { try { return this.node.lock(isDeep, isSessionScoped); } catch (LockException e) { // its not an exception yet, still got time lockException = e; } Thread.yield(); } // could not get lock throw lockException; } /** * Returns the Lock object that applies to this node. This may be either a lock on this node itself or a deep lock * on a node above this node. * @throws LockException If no lock applies to this node, a LockException is thrown. * @throws RepositoryException if an error occurs */ public Lock getLock() throws LockException, RepositoryException { return this.node.getLock(); } /** * Removes the lock on this node. Also removes the properties jcr:lockOwner and jcr:lockIsDeep from this node. These * changes are persisted automatically; <b>there is no need to call save</b>. * @throws LockException if either does not currently hold a lock, or holds a lock for which this Session does not * have the correct lock token * @throws RepositoryException if an error occurs */ public void unlock() throws LockException, RepositoryException { this.node.unlock(); } /** * Returns true if this node holds a lock; otherwise returns false. To hold a lock means that this node has actually * had a lock placed on it specifically, as opposed to just having a lock apply to it due to a deep lock held by a * node above. * @return a boolean * @throws RepositoryException if an error occurs */ public boolean holdsLock() throws RepositoryException { return this.node.holdsLock(); } /** * Returns true if this node is locked either as a result of a lock held by this node or by a deep lock on a node * above this node; otherwise returns false. * @return a boolean * @throws RepositoryException if an error occurs */ public boolean isLocked() throws RepositoryException { return this.node.isLocked(); } /** * get workspace to which this node attached to * @throws RepositoryException if unable to get this node session */ public Workspace getWorkspace() throws RepositoryException { return this.node.getSession().getWorkspace(); } /** * checks if this node has a sub node with name MetaData * @return true if MetaData exists */ public boolean hasMetaData() { try { return this.node.hasNode("MetaData"); } catch (RepositoryException re) { log.debug(re.getMessage(), re); } return false; } /** * @see java.lang.Object#toString() */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(getClass().getName()); buffer.append("["); if (this.node != null) { buffer.append(getHandle()); } buffer.append("]"); return buffer.toString(); } /** * Implement this interface to be used as node filter by getChildren() */ public interface ContentFilter { /** * Test if this content should be included in a resultant collection * @param content * @return if true this will be a part of collection */ public boolean accept(Content content); } }