/** * Licensed 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.brixcms.jcr.wrapper; import org.brixcms.Brix; import org.brixcms.jcr.api.JcrNode; import org.brixcms.jcr.api.JcrSession; import org.brixcms.jcr.api.wrapper.NodeWrapper; import org.brixcms.plugin.site.folder.FolderNodePlugin; import org.brixcms.plugin.site.resource.ResourceNodePlugin; import org.brixcms.web.util.validators.NodeNameValidator; import javax.jcr.Node; import java.util.Calendar; import java.util.Date; /** * Base wrapper that all other wrappers in Brix must extend. Contains convenience methods for setting/getting node type * and common properties. * <p/> * Every node obtained from {@link JcrSession} in {@link Brix} is guaranteed to extend {@link BrixNode}. * * @author Matej Knopp */ public class BrixNode extends NodeWrapper { /** * Mixin for brix:node */ public static final String JCR_TYPE_BRIX_NODE = Brix.NS_PREFIX + "node"; /** * Mixin for hidden nodes. */ public static final String JCR_MIXIN_BRIX_HIDDEN = Brix.NS_PREFIX + "hidden"; /** * Property for storing node type */ private static final String JCR_PROP_NODE_TYPE = Brix.NS_PREFIX + "nodeType"; /** * Property for storing last modified date */ private static final String JCR_PROP_LAST_MODIFIED = Brix.NS_PREFIX + "lastModified"; /** * Property for storing id of the last user that has modified this node */ private static final String JCR_PROP_LAST_MODIFIED_BY = Brix.NS_PREFIX + "lastModifiedBy"; /** * Property for storing date when node was first time saved */ private static final String JCR_PROP_CREATED = Brix.NS_PREFIX + "created"; /** * Property for storing user id for user that has created this node */ private static final String JCR_PROP_CREATED_BY = Brix.NS_PREFIX + "createdBy"; /** * Returns the type of given node. * <p/> * TODO: There are two special cases (resource, type) that create special dependency on the site plugin. The folder * and Resource nodes should be moved away from site plugin. * * @param node * @return */ public static String getNodeType(JcrNode node) { if (node.hasProperty(JCR_PROP_NODE_TYPE)) { return node.getProperty(JCR_PROP_NODE_TYPE).getString(); } if (node.isNodeType("nt:file")) { if (node.hasNode("jcr:content")) { return ResourceNodePlugin.TYPE; } } else if (node.isNodeType("nt:folder") || node.getDepth() == 0) { // TODO: Move the constant return FolderNodePlugin.TYPE; } return null; } /** * Convenience method that checks if the node name is a valid JCR node name. * * @param nodeName * @return */ public static boolean isValidNodeName(String nodeName) { if (nodeName == null) { return false; } else { for (int i = 0; i < nodeName.length(); ++i) { if (NodeNameValidator.isForbidden(nodeName.charAt(i))) { return false; } } return true; } } /** * Wrapper constructor. Wraps the delegate node. * * @param delegate * @param session */ public BrixNode(Node delegate, JcrSession session) { super(delegate, session); } /** * Convenience method for obtaining Brix instance. This is the preferred way to obtain the instance. * * @return brix instance */ public Brix getBrix() { return Brix.get(); } /** * Returns the date of node creation. * * @return * @see #touch() */ public Date getCreated() { if (hasProperty(JCR_PROP_CREATED)) { return getProperty(JCR_PROP_CREATED).getDate().getTime(); } else { return null; } } /** * Returns the user id of use that has created this node. * * @return * @see #touch() */ public String getCreatedBy() { if (hasProperty(JCR_PROP_CREATED_BY)) { return getProperty(JCR_PROP_CREATED_BY).getString(); } else { return "Unknown"; } } /** * Returns the date of last modification. * * @return * @see #touch() */ public Date getLastModified() { if (hasProperty(JCR_PROP_LAST_MODIFIED)) { return getProperty(JCR_PROP_LAST_MODIFIED).getDate().getTime(); } else { return null; } } /** * Returns the user id of the last user that has modified this node. * * @return * @see #touch() */ public String getLastModifiedBy() { if (hasProperty(JCR_PROP_LAST_MODIFIED_BY)) { return getProperty(JCR_PROP_LAST_MODIFIED_BY).getString(); } else { return "Unknown"; } } /** * Returns the type of this node if it has any type assigned. * * @return node type or <code>null</code> if the node has no type assigned */ public String getNodeType() { return getNodeType(this); } /** * Returns the required protocol for this node. If the required protocol is not {@link Protocol#PRESERVE_CURRENT} * and current page protocol is different, Brix will redirect to required protocol. * * @return */ public Protocol getRequiredProtocol() { return Protocol.PRESERVE_CURRENT; } /** * Returns the user visible node name. In most cases, this would be the same as node name, but it can be overridden * by the wrapper. * * @return user visible node name */ public String getUserVisibleName() { return getName(); } /** * Returns the user visible node type. By default returns empty string, can be overridden by the wrapper. * * @return user visible node type */ public String getUserVisibleType() { return ""; } public boolean isFolder() { return isNodeType("nt:folder"); } /** * Sets the hidden state of this node. Hidden node is usually considered part of parent node and should not be * visible to user on it's own. * * @param hidden */ public void setHidden(boolean hidden) { if (isHidden() != hidden) { if (hidden) { addMixin(JCR_MIXIN_BRIX_HIDDEN); } else { removeMixin(JCR_MIXIN_BRIX_HIDDEN); } } } /** * Returns whether this node is hidden. * * @return * @see #setHidden(boolean) */ public boolean isHidden() { return isNodeType(JCR_MIXIN_BRIX_HIDDEN); } /** * Sets the node type for this node. * * @param type */ public void setNodeType(String type) { if (!isNodeType(JCR_TYPE_BRIX_NODE)) { addMixin(JCR_TYPE_BRIX_NODE); } setProperty(JCR_PROP_NODE_TYPE, type); } /** * Touches this node. Touch updates the created, createdBy, lastModified, lastModifiedBy properties. In order for * these properties to reflect the actual state {@link #touch()} must be invoked every time node is being saved. * This happens automatically when {@link Node#save()} is invoked, however, if only session is saved {@link * #touch()} must be called explicitly. */ public void touch() { if (!isNodeType(JCR_TYPE_BRIX_NODE)) { addMixin(JCR_TYPE_BRIX_NODE); } String user = getSession().getUserID(); Calendar now = Calendar.getInstance(); if (!hasProperty(JCR_PROP_CREATED)) { setProperty(JCR_PROP_CREATED, now); } if (!hasProperty(JCR_PROP_CREATED_BY)) { setProperty(JCR_PROP_CREATED_BY, user); } setProperty(JCR_PROP_LAST_MODIFIED, now); setProperty(JCR_PROP_LAST_MODIFIED_BY, user); } public enum Protocol { HTTP, HTTPS, PRESERVE_CURRENT } }