/**
* This file Copyright (c) 2012 Magnolia International
* Ltd. (http://www.magnolia-cms.com). All rights reserved.
*
*
* This file is dual-licensed under both the Magnolia
* Network Agreement and the GNU General Public License.
* You may elect to use one or the other of these licenses.
*
* This file is distributed in the hope that it will be
* useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
* Redistribution, except as permitted by whichever of the GPL
* or MNA you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or
* modify this file under the terms of the GNU General
* Public License, Version 3, as published by the Free Software
* Foundation. You should have received a copy of the GNU
* General Public License, Version 3 along with this program;
* if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 2. For the Magnolia Network Agreement (MNA), this file
* and the accompanying materials are made available under the
* terms of the MNA which accompanies this distribution, and
* is available at http://www.magnolia-cms.com/mna.html
*
* Any modifications to this file must keep this entire header
* intact.
*
*/
package info.magnolia.jcr.util;
import info.magnolia.context.MgnlContext;
import info.magnolia.logging.AuditLoggingUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.Calendar;
/**
* Magnolia defined NodeTypes together with their properties and some convenience methods.
*/
public class NodeTypes {
private static final Logger log = LoggerFactory.getLogger(NodeTypes.class);
/** Namespace for Magnolia extensions. */
public static final String MGNL_PREFIX = "mgnl:";
/** Namespace for jcr properties. */
public static final String JCR_PREFIX = "jcr:";
/** Default suffix for userName keeping properties. */
private static final String BY = "By";
/**
* Represents the mixin mgnl:lastModified.
*/
public static class LastModified {
public static final String NAME = MGNL_PREFIX + "lastModified";
public static final String LAST_MODIFIED = NAME;
public static final String LAST_MODIFIED_BY = LAST_MODIFIED + BY;
/**
* Returns the date when this node was last modified. If the no modification date has been stored on the node this
* method return the creation date if set, otherwise null is returned.
*/
public static Calendar getLastModified(Node node) throws RepositoryException {
return node.hasProperty(LAST_MODIFIED) ? node.getProperty(LAST_MODIFIED).getDate() : Created.getCreated(node);
}
/**
* Returns the name of the user that last modified the node. If no modification has been stored on the node
* this method return the name of the user that created the node if set, otherwise null is returned.
*/
public static String getLastModifiedBy(Node node) throws RepositoryException {
return node.hasProperty(LAST_MODIFIED_BY) ? node.getProperty(LAST_MODIFIED_BY).getString() : Created.getCreatedBy(node);
}
/**
* Sets the date of modification to current Calendar and uses {@link info.magnolia.context.MgnlContext} to set the name of the user.
*/
public static void update(Node node) throws RepositoryException {
update(node, getCurrentUserName(), getCurrentCalendar());
}
/**
* Sets the date of modification and the name of the user modifying a node.
*/
public static void update(Node node, String userName, Calendar lastModified) throws RepositoryException {
checkNodeType(node, LastModified.NAME, LAST_MODIFIED, LAST_MODIFIED_BY);
node.setProperty(LAST_MODIFIED, lastModified);
node.setProperty(LAST_MODIFIED_BY, userName);
AuditLoggingUtil.log(AuditLoggingUtil.ACTION_MODIFY, node.getSession().getWorkspace().getName(), node
.getPrimaryNodeType().getName(), node.getName());
}
}
/**
* Represents the mixin mgnl:activatable.
*/
public static class Activatable {
public static final String NAME = MGNL_PREFIX + "activatable";
public static final String LAST_ACTIVATED = MGNL_PREFIX + "lastActivated";
public static final String LAST_ACTIVATED_BY = LAST_ACTIVATED + BY;
public static final String ACTIVATION_STATUS = MGNL_PREFIX + "activationStatus";
public static final int ACTIVATION_STATUS_NOT_ACTIVATED = 0;
public static final int ACTIVATION_STATUS_MODIFIED = 1;
public static final int ACTIVATION_STATUS_ACTIVATED = 2;
/**
* Returns the activation status of the node. Returns one of the constants:
* <ul>
* <li>{@link #ACTIVATION_STATUS_NOT_ACTIVATED} if the node has not been activated</li>
* <li>{@link #ACTIVATION_STATUS_MODIFIED} has been activated and subsequently modified</li>
* <li>{@link #ACTIVATION_STATUS_ACTIVATED} has been activated and not modified since</li>
* </ul>
*/
public static int getActivationStatus(Node node) throws RepositoryException {
if (!isActivated(node)) {
// never activated or deactivated
return ACTIVATION_STATUS_NOT_ACTIVATED;
}
Calendar lastModified = LastModified.getLastModified(node);
Calendar lastActivated = getLastActivated(node);
if (lastModified != null && lastModified.after(lastActivated)) {
// node has been modified after last activation
return ACTIVATION_STATUS_MODIFIED;
}
// activated and not modified ever since
return ACTIVATION_STATUS_ACTIVATED;
}
/**
* Returns true if the node has been activated.
*/
public static boolean isActivated(Node node) throws RepositoryException {
return node.hasProperty(ACTIVATION_STATUS) && node.getProperty(ACTIVATION_STATUS).getBoolean();
}
/**
* Returns the date when the node was last activated or null if no activation date has been stored on the node.
*/
public static Calendar getLastActivated(Node node) throws RepositoryException {
return node.hasProperty(LAST_ACTIVATED) ? node.getProperty(LAST_ACTIVATED).getDate() : null;
}
/**
* Returns the name of the user that last activated the node or null if no activating user has been stored on the node.
*/
public static String getLastActivatedBy(Node node) throws RepositoryException {
return node.hasProperty(LAST_ACTIVATED_BY) ? node.getProperty(LAST_ACTIVATED_BY).getString() : null;
}
/**
* Sets the name of the user that performed the most recent activation as well as to current time.
*/
public static void update(Node node, String userName, boolean isActivated) throws RepositoryException {
checkNodeType(node, Activatable.NAME, LAST_ACTIVATED, LAST_ACTIVATED_BY, ACTIVATION_STATUS);
node.setProperty(LAST_ACTIVATED, getCurrentCalendar());
node.setProperty(LAST_ACTIVATED_BY, userName);
node.setProperty(ACTIVATION_STATUS, isActivated);
}
}
/**
* Represents the mixin mgnl:created.
*/
public static class Created {
public static final String NAME = MGNL_PREFIX + "created";
public static final String CREATED = NAME;
public static final String CREATED_BY = CREATED + BY;
/**
* Returns the creation date of a node or null if creation date isn't set.
*/
public static Calendar getCreated(Node node) throws RepositoryException {
return node.hasProperty(CREATED) ? node.getProperty(CREATED).getDate() : null;
}
/**
* Returns the name of the user that created a node.
*/
public static String getCreatedBy(Node node) throws RepositoryException {
return node.hasProperty(CREATED_BY) ? node.getProperty(CREATED_BY).getString() : null;
}
/**
* Sets the current date as the node's creation date and uses {@link info.magnolia.context.MgnlContext} to set the name of the creating
* user. Used with nodes having the <code>mgnl:created</code> mixin.
*/
public static void set(Node node) throws RepositoryException {
set(node, getCurrentUserName(), getCurrentCalendar());
}
/**
* Sets the supplied date as the node's creation date and sets the name of the creating user. Also sets the date of
* modification and the user last having modified the node to the same values. Used with nodes having the
* <code>mgnl:created</code> mixin.
*/
static void set(Node node, String userName, Calendar created) throws RepositoryException {
checkNodeType(node, NAME, CREATED, CREATED_BY);
node.setProperty(CREATED, created);
node.setProperty(CREATED_BY, userName);
LastModified.update(node, userName, created);
}
}
/**
* Represents the mixin mgnl:renderable.
*/
public static class Renderable {
public static final String NAME = MGNL_PREFIX + "renderable";
public static final String TEMPLATE = MGNL_PREFIX + "template";
/**
* Returns the template assigned to the node or null of none has been assigned. Used with nodes having the
* <code>mgnl:renderable</code> mixin.
*/
public static String getTemplate(Node node) throws RepositoryException {
return node.hasProperty(TEMPLATE) ? node.getProperty(TEMPLATE).getString() : null;
}
/**
* Sets the template assigned to the node. Used with nodes having the <code>mgnl:renderable</code> mixin.
*/
public static void set(Node node, String template) throws RepositoryException {
checkNodeType(node, NAME, TEMPLATE);
node.setProperty(TEMPLATE, template);
}
}
/**
* Represents the mixin mgnl:deleted.
*/
public static class Deleted {
public static final String NAME = MGNL_PREFIX + "deleted";
public static final String DELETED = NAME;
public static final String DELETED_BY = DELETED + BY;
public static final String COMMENT = MGNL_PREFIX + "comment";
/**
* Returns the date when the node was deleted or null if no deletion date has been stored on the node.
*/
public static Calendar getDeleted(Node node) throws RepositoryException {
return node.hasProperty(DELETED) ? node.getProperty(DELETED).getDate() : null;
}
/**
* Returns the name of the user that deleted the node or null if no deleting user has been stored on the node.
*/
public static String getDeletedBy(Node node) throws RepositoryException {
return node.hasProperty(DELETED_BY) ? node.getProperty(DELETED_BY).getString() : null;
}
/**
* Returns the comment set when then node was last deleted or null if no comment has been set.
*/
public static String getComment(Node node) throws RepositoryException {
return node.hasProperty(COMMENT) ? node.getProperty(COMMENT).getString() : null;
}
public static void set(Node node, String comment) throws RepositoryException {
checkNodeType(node, NAME, DELETED, DELETED_BY, COMMENT);
node.setProperty(DELETED, getCurrentCalendar());
node.setProperty(DELETED_BY, getCurrentUserName());
node.setProperty(COMMENT, comment);
}
}
/**
* Represents the mixin mgnl:versionable.
*/
public static class Versionable {
public static final String NAME = MGNL_PREFIX + "versionable";
public static final String COMMENT = Deleted.COMMENT;
/**
* Returns the comment set when then node was last versioned or null if no comment has been set.
*/
public static String getComment(Node node) throws RepositoryException {
return node.hasProperty(COMMENT) ? node.getProperty(COMMENT).getString() : null;
}
/**
* Set the versioning comment on the node.
*/
public static void set(Node node, String comment) throws RepositoryException{
checkNodeType(node, NAME, COMMENT);
node.setProperty(COMMENT, comment);
}
}
/**
* Represents the nodeType mgnl:folder.
*/
public static class Folder {
public static final String NAME = MGNL_PREFIX + "folder";
}
/**
* Represents the nodeType mgnl:resource.
*/
public static class Resource {
public static final String NAME = MGNL_PREFIX + "resource";
}
/**
* Represents the nodeType mgnl:content.
*/
public static class Content {
public static final String NAME = MGNL_PREFIX + "content";
}
/**
* Represents the nodeType mgnl:contentNode.
*/
public static class ContentNode {
public static final String NAME = MGNL_PREFIX + "contentNode";
}
/**
* Represents the nodeType mgnl:nodeData.
*/
public static class NodeData {
public static final String NAME = MGNL_PREFIX + "nodeData";
}
/**
* Represents the nodeType mgnl:page.
*/
public static class Page {
public static final String NAME = MGNL_PREFIX + "page";
}
/**
* Represents the nodeType mgnl:area.
*/
public static class Area {
public static final String NAME = MGNL_PREFIX + "area";
}
/**
* Represents the nodeType mgnl:component.
*/
public static class Component {
public static final String NAME = MGNL_PREFIX + "component";
}
/**
* Represents the nodeType mgnl:user.
*/
public static class User {
public static final String NAME = MGNL_PREFIX + "user";
}
/**
* Represents the nodeType mgnl:role.
*/
public static class Role {
public static final String NAME = MGNL_PREFIX + "role";
}
/**
* Represents the nodeType mgnl:group.
*/
public static class Group {
public static final String NAME = MGNL_PREFIX + "group";
}
/**
* Represents the nodeType mgnl:reserve.
*/
public static class System {
public static final String NAME = MGNL_PREFIX + "reserve";
}
/**
* Represents the nodeType mgnl:metaData.
* Is basically obsolete since MetaData as mixin but could still be used in customers code,
* hence it has to stay for quite a while.
*/
public static class MetaData {
public static final String NAME = MGNL_PREFIX + "metaData";
}
protected static String getCurrentUserName() {
return MgnlContext.getUser().getName();
}
protected static Calendar getCurrentCalendar() {
return Calendar.getInstance();
}
public static void checkNodeType(Node node, String nodeType, String... propertyNames) throws RepositoryException {
if (!node.isNodeType(nodeType)) {
log.warn("Trying to set property/ies '" + StringUtils.join(propertyNames, ", ") + "' although the node '" + node.getPath() + "' with PrimaryType '" + node.getPrimaryNodeType().getName() + "' is not of type '" + nodeType + "'!");
}
}
}