/**
* This file Copyright (c) 2003-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.cms.core;
import info.magnolia.cms.security.AccessManager;
import info.magnolia.jcr.util.NodeTypes;
import info.magnolia.jcr.util.PropertyUtil;
import info.magnolia.repository.RepositoryConstants;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Represents the meta data of a node, its creation date, modification date, assigned template etc.
*
* As of 5.0 the meta data is stored directly on the node itself using mixins rather than in a subnode named MetaData.
* With this change this class was deprecated and replaced with corresponding methods in
* {@link info.magnolia.jcr.util.NodeUtil}.
*
* @deprecated since 5.0 - use instead the corresponding methods in NodeUtil
*/
public class MetaData {
private static final Logger log = LoggerFactory.getLogger(MetaData.class);
/**
* Top level atoms viewed as metadata of the specified content these must be set by the authoring system itself, but
* could be changed via custom templates if necessary.
*/
/**
* @deprecated since 5.0 - no longer supported
*/
public static final String TITLE = "title";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#CREATED} instead
*/
public static final String CREATION_DATE = "creationdate";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#LAST_MODIFIED} instead
*/
public static final String LAST_MODIFIED = "lastmodified";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#LAST_ACTIVATED} instead
*/
public static final String LAST_ACTION = "lastaction";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#LAST_MODIFIED_BY} instead
*/
public static final String AUTHOR_ID = "authorid";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#LAST_ACTIVATED_BY} instead
*/
public static final String ACTIVATOR_ID = "activatorid";
/**
* Template assigned to the node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#TEMPLATE} instead
*/
public static final String TEMPLATE = "template";
/**
* @deprecated since 5.0 - no longer supported
*/
public static final String TEMPLATE_TYPE = "templatetype";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS} instead
*/
public static final String ACTIVATED = "activated";
/**
* Name of the node hosting the MetaData.
*
* @deprecated since 5.0 - there's no longer such a subnode
*/
public static final String DEFAULT_META_NODE = "MetaData";
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_NOT_ACTIVATED} instead
*/
public static final int ACTIVATION_STATUS_NOT_ACTIVATED = NodeTypes.Activatable.ACTIVATION_STATUS_NOT_ACTIVATED;
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_MODIFIED} instead
*/
public static final int ACTIVATION_STATUS_MODIFIED = NodeTypes.Activatable.ACTIVATION_STATUS_MODIFIED;
/**
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_ACTIVATED} instead
*/
public static final int ACTIVATION_STATUS_ACTIVATED = NodeTypes.Activatable.ACTIVATION_STATUS_ACTIVATED;
/**
* Since 5.0 this is the working node itself.
*/
private Node node;
/**
* @param workingNode
* current <code>Node</code> on which <code>MetaData</code> is requested
* @param ignoredAccessManager
* no longer required hence use other constructor.
*
* @deprecated since 4.5 use MetaData(Node) instead.
*/
protected MetaData(Node workingNode, AccessManager ignoredAccessManager) {
this(workingNode);
}
/**
* @param workingNode
* current <code>Node</code> on which <code>MetaData</code> is requested
*/
public MetaData(Node workingNode) {
this.node = workingNode;
}
/**
* Maps property names from the names used when we had a MetaData sub node to their replacements on mixins on the
* working node itself.
*/
private static Map<String, String> propertyMappings = new ConcurrentHashMap<String, String>();
static {
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATION_DATE, NodeTypes.Created.CREATED);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + LAST_MODIFIED, NodeTypes.LastModified.LAST_MODIFIED);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + LAST_ACTION, NodeTypes.Activatable.LAST_ACTIVATED);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + AUTHOR_ID, NodeTypes.LastModified.LAST_MODIFIED_BY);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + ACTIVATOR_ID, NodeTypes.Activatable.LAST_ACTIVATED_BY);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + TEMPLATE, NodeTypes.Renderable.TEMPLATE);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + ACTIVATED, NodeTypes.Activatable.ACTIVATION_STATUS);
propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":comment", NodeTypes.Versionable.COMMENT);
}
/**
* Returns the property name to use including its prefix.
*
* @return name with namespace prefix
*/
private String getInternalPropertyName(String name) {
if (StringUtils.indexOf(name, ":") < 0) {
name = RepositoryConstants.NAMESPACE_PREFIX + ":" + name;
}
String newName = propertyMappings.get(name);
if (newName == null) {
throw new IllegalArgumentException("Unsupported meta data property: " + name);
}
return newName;
}
/**
* @return value of property TITLE if it's around on working node
*
* @deprecated since 5.0 - only for backwards compatibility.
*/
public String getTitle() {
return getStringProperty(TITLE);
}
/**
* Will set value of property TITLE on working node.
*
* @deprecated since 5.0 - only for backwards compatibility.
*/
public void setTitle(String value) {
setProperty(TITLE, value);
}
/**
* Part of metadata, adds creation date of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#set(Node)}
*/
public void setCreationDate() {
Calendar value = new GregorianCalendar(TimeZone.getDefault());
setProperty(CREATION_DATE, value);
}
/**
* Part of metadata, get creation date of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#getCreated(Node)}
*/
public Calendar getCreationDate() {
return this.getDateProperty(CREATION_DATE);
}
/**
* Part of metadata, adds activated status of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
*/
public void setActivated() {
setProperty(ACTIVATED, true);
}
/**
* Part of metadata, adds activated status of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
*/
public void setUnActivated() {
setProperty(ACTIVATED, false);
}
/**
* Part of metadata, get last activated status of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#isActivated(javax.jcr.Node)}
*/
public boolean getIsActivated() {
return getBooleanProperty(ACTIVATED);
}
/**
* Returns one of the ACTIVATION_STATUS_* constants.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getActivationStatus(javax.jcr.Node)}
*/
public int getActivationStatus() {
if (getIsActivated()) {
if (getModificationDate() != null && getModificationDate().after(getLastActionDate())) {
// node has been modified after last activation
return ACTIVATION_STATUS_MODIFIED;
}
// activated and not modified ever since
return ACTIVATION_STATUS_ACTIVATED;
}
// never activated or deactivated
return ACTIVATION_STATUS_NOT_ACTIVATED;
}
/**
* Part of metadata, adds activated date of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
*/
public void setLastActivationActionDate() {
Calendar value = new GregorianCalendar(TimeZone.getDefault());
setProperty(LAST_ACTION, value);
}
/**
* Part of metadata, get last activated/de- date of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getLastActivated(javax.jcr.Node)}
*/
public Calendar getLastActionDate() {
return getDateProperty(LAST_ACTION);
}
/**
* Part of metadata, adds modification date of the current node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#update(javax.jcr.Node)}
*/
public void setModificationDate() {
Calendar value = new GregorianCalendar(TimeZone.getDefault());
setProperty(LAST_MODIFIED, value);
}
/**
* Get last modified date of the node to which this meta data belongs or creation date in case content was not
* modified since.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#getLastModified(Node)}
*/
public Calendar getModificationDate() {
Calendar modDate = getDateProperty(LAST_MODIFIED);
if (modDate == null) {
modDate = getCreationDate();
}
return modDate;
}
/**
* Part of metadata, last known author of this node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#getLastModifiedBy(javax.jcr.Node)}
*/
public String getAuthorId() {
return getStringProperty(AUTHOR_ID);
}
/**
* Part of metadata, current logged-in author who did some action on this page.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#update(javax.jcr.Node, String, java.util.Calendar)}
*/
public void setAuthorId(String value) {
setProperty(AUTHOR_ID, value);
}
/**
* Part of metadata, last known activator of this node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getLastActivatedBy(javax.jcr.Node)}
*/
public String getActivatorId() {
return getStringProperty(ACTIVATOR_ID);
}
/**
* Part of metadata, current logged-in author who last activated this page.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)} to directly set userName and true false.
*/
public void setActivatorId(String value) {
setProperty(ACTIVATOR_ID, value);
}
/**
* Part of metadata, template which will be used to render content of this node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#getTemplate(javax.jcr.Node)}
*/
public String getTemplate() {
return getStringProperty(TEMPLATE);
}
/**
* Part of metadata, template which will be used to render content of this node.
*
* @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#set(javax.jcr.Node, String)}
*/
public void setTemplate(String value) {
setProperty(TEMPLATE, value);
}
public void setProperty(String name, String value) {
setJCRProperty(name, value);
}
public void setProperty(String name, long value) {
setJCRProperty(name, value);
}
public void setProperty(String name, double value) {
setJCRProperty(name, value);
}
public void setProperty(String name, boolean value) {
setJCRProperty(name, value);
}
public void setProperty(String name, Calendar value) {
setJCRProperty(name, value);
}
private void setJCRProperty(String name, Object value) {
final String propName = this.getInternalPropertyName(name);
try {
PropertyUtil.setProperty(node, propName, value);
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
}
public boolean getBooleanProperty(String name) {
try {
final Property property = getJCRProperty(name);
if (property != null) {
return property.getBoolean();
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
return false;
}
public double getDoubleProperty(String name) {
try {
final Property property = getJCRProperty(name);
if (property != null) {
return property.getDouble();
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
return 0d;
}
public long getLongProperty(String name) {
try {
final Property property = getJCRProperty(name);
if (property != null) {
return property.getLong();
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
return 0L;
}
public String getStringProperty(String name) {
try {
final Property property = getJCRProperty(name);
if (property != null) {
return property.getString();
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
return StringUtils.EMPTY;
}
public Calendar getDateProperty(String name) {
try {
final Property property = getJCRProperty(name);
if (property != null) {
return property.getDate();
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
return null;
}
/**
* remove specified property.
*
* @param name
* of the property to be removed
* @throws PathNotFoundException
* if property does not exist
* @throws RepositoryException
* if unable to remove
*/
public void removeProperty(String name) throws PathNotFoundException, RepositoryException {
this.node.getProperty(this.getInternalPropertyName(name)).remove();
}
private Property getJCRProperty(String name) throws RepositoryException {
final String propName = this.getInternalPropertyName(name);
try {
return node.getProperty(propName);
} catch (PathNotFoundException re) {
log.debug("PathNotFoundException for property [{}] in node {}", propName, node);
}
return null;
}
}