View Javadoc

1   /**
2    * This file Copyright (c) 2003-2013 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.core;
35  
36  import info.magnolia.cms.security.AccessManager;
37  import info.magnolia.jcr.util.NodeTypes;
38  import info.magnolia.jcr.util.PropertyUtil;
39  import info.magnolia.repository.RepositoryConstants;
40  
41  import java.util.Calendar;
42  import java.util.GregorianCalendar;
43  import java.util.Map;
44  import java.util.TimeZone;
45  import java.util.concurrent.ConcurrentHashMap;
46  
47  import javax.jcr.Node;
48  import javax.jcr.PathNotFoundException;
49  import javax.jcr.Property;
50  import javax.jcr.RepositoryException;
51  
52  import org.apache.commons.lang.StringUtils;
53  import org.slf4j.Logger;
54  import org.slf4j.LoggerFactory;
55  
56  /**
57   * Represents the meta data of a node, its creation date, modification date, assigned template etc.
58   *
59   * As of 5.0 the meta data is stored directly on the node itself using mixins rather than in a subnode named MetaData.
60   * With this change this class was deprecated and replaced with corresponding methods in
61   * {@link info.magnolia.jcr.util.NodeUtil}.
62   *
63   * @deprecated since 5.0 - use instead the corresponding methods in NodeUtil
64   */
65  public class MetaData {
66      private static final Logger log = LoggerFactory.getLogger(MetaData.class);
67  
68      /**
69       * Top level atoms viewed as metadata of the specified content these must be set by the authoring system itself, but
70       * could be changed via custom templates if necessary.
71       */
72  
73      /**
74       * @deprecated since 5.0 - no longer supported
75       */
76      public static final String TITLE = "title";
77  
78      /**
79       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#CREATED} instead
80       */
81      public static final String CREATION_DATE = "creationdate";
82  
83      /**
84       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#LAST_MODIFIED} instead
85       */
86      public static final String LAST_MODIFIED = "lastmodified";
87  
88      /**
89       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#LAST_ACTIVATED} instead
90       */
91      public static final String LAST_ACTION = "lastaction";
92  
93      /**
94       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#LAST_MODIFIED_BY} instead
95       */
96      public static final String AUTHOR_ID = "authorid";
97  
98      /**
99       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#LAST_ACTIVATED_BY} instead
100      */
101     public static final String ACTIVATOR_ID = "activatorid";
102 
103     /**
104      * Template assigned to the node.
105      *
106      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#TEMPLATE} instead
107      */
108     public static final String TEMPLATE = "template";
109 
110     /**
111      * @deprecated since 5.0 - no longer supported
112      */
113     public static final String TEMPLATE_TYPE = "templatetype";
114 
115     /**
116      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS} instead
117      */
118     public static final String ACTIVATED = "activated";
119 
120     /**
121      * Name of the node hosting the MetaData.
122      *
123      * @deprecated since 5.0 - there's no longer such a subnode
124      */
125     public static final String DEFAULT_META_NODE = "MetaData";
126 
127     /**
128      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_NOT_ACTIVATED} instead
129      */
130     public static final int ACTIVATION_STATUS_NOT_ACTIVATED = NodeTypes.Activatable.ACTIVATION_STATUS_NOT_ACTIVATED;
131 
132     /**
133      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_MODIFIED} instead
134      */
135     public static final int ACTIVATION_STATUS_MODIFIED = NodeTypes.Activatable.ACTIVATION_STATUS_MODIFIED;
136 
137     /**
138      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_ACTIVATED} instead
139      */
140     public static final int ACTIVATION_STATUS_ACTIVATED = NodeTypes.Activatable.ACTIVATION_STATUS_ACTIVATED;
141 
142     /**
143      * Since 5.0 this is the working node itself.
144      */
145     private Node node;
146 
147     /**
148      * @param workingNode
149      *            current <code>Node</code> on which <code>MetaData</code> is requested
150      * @param ignoredAccessManager
151      *            no longer required hence use other constructor.
152      *
153      * @deprecated since 4.5 use MetaData(Node) instead.
154      */
155     protected MetaData(Node workingNode, AccessManager ignoredAccessManager) {
156         this(workingNode);
157     }
158 
159     /**
160      * @param workingNode
161      *            current <code>Node</code> on which <code>MetaData</code> is requested
162      */
163     public MetaData(Node workingNode) {
164         this.node = workingNode;
165     }
166 
167     /**
168      * Maps property names from the names used when we had a MetaData sub node to their replacements on mixins on the
169      * working node itself.
170      */
171     private static Map<String, String> propertyMappings = new ConcurrentHashMap<String, String>();
172 
173     static {
174         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATION_DATE, NodeTypes.Created.CREATED);
175         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + LAST_MODIFIED, NodeTypes.LastModified.LAST_MODIFIED);
176         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + LAST_ACTION, NodeTypes.Activatable.LAST_ACTIVATED);
177         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + AUTHOR_ID, NodeTypes.LastModified.LAST_MODIFIED_BY);
178         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + ACTIVATOR_ID, NodeTypes.Activatable.LAST_ACTIVATED_BY);
179         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + TEMPLATE, NodeTypes.Renderable.TEMPLATE);
180         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + ACTIVATED, NodeTypes.Activatable.ACTIVATION_STATUS);
181         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":comment", NodeTypes.Versionable.COMMENT);
182     }
183 
184     /**
185      * Returns the property name to use including its prefix.
186      *
187      * @return name with namespace prefix
188      */
189     private String getInternalPropertyName(String name) {
190         if (StringUtils.indexOf(name, ":") < 0) {
191             name = RepositoryConstants.NAMESPACE_PREFIX + ":" + name;
192         }
193 
194         String newName = propertyMappings.get(name);
195 
196         if (newName == null) {
197             throw new IllegalArgumentException("Unsupported meta data property: " + name);
198         }
199 
200         return newName;
201     }
202 
203     /**
204      * @return value of property TITLE if it's around on working node
205      *
206      * @deprecated since 5.0 - only for backwards compatibility.
207      */
208     public String getTitle() {
209         return getStringProperty(TITLE);
210     }
211 
212     /**
213      * Will set value of property TITLE on working node.
214      *
215      * @deprecated since 5.0 - only for backwards compatibility.
216      */
217     public void setTitle(String value) {
218         setProperty(TITLE, value);
219     }
220 
221     /**
222      * Part of metadata, adds creation date of the current node.
223      *
224      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#set(Node)}
225      */
226     public void setCreationDate() {
227         Calendar value = new GregorianCalendar(TimeZone.getDefault());
228         setProperty(CREATION_DATE, value);
229     }
230 
231     /**
232      * Part of metadata, get creation date of the current node.
233      *
234      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#getCreated(Node)}
235      */
236     public Calendar getCreationDate() {
237         return this.getDateProperty(CREATION_DATE);
238     }
239 
240     /**
241      * Part of metadata, adds activated status of the current node.
242      *
243      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
244      */
245     public void setActivated() {
246         setProperty(ACTIVATED, true);
247     }
248 
249     /**
250      * Part of metadata, adds activated status of the current node.
251      *
252      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
253      */
254     public void setUnActivated() {
255         setProperty(ACTIVATED, false);
256     }
257 
258     /**
259      * Part of metadata, get last activated status of the current node.
260      *
261      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#isActivated(javax.jcr.Node)}
262      */
263     public boolean getIsActivated() {
264         return getBooleanProperty(ACTIVATED);
265     }
266 
267     /**
268      * Returns one of the ACTIVATION_STATUS_* constants.
269      *
270      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getActivationStatus(javax.jcr.Node)}
271      */
272     public int getActivationStatus() {
273         if (getIsActivated()) {
274             if (getModificationDate() != null && getModificationDate().after(getLastActionDate())) {
275                 // node has been modified after last activation
276                 return ACTIVATION_STATUS_MODIFIED;
277             }
278             // activated and not modified ever since
279             return ACTIVATION_STATUS_ACTIVATED;
280         }
281         // never activated or deactivated
282         return ACTIVATION_STATUS_NOT_ACTIVATED;
283     }
284 
285     /**
286      * Part of metadata, adds activated date of the current node.
287      *
288      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
289      */
290     public void setLastActivationActionDate() {
291         Calendar value = new GregorianCalendar(TimeZone.getDefault());
292         setProperty(LAST_ACTION, value);
293     }
294 
295     /**
296      * Part of metadata, get last activated/de- date of the current node.
297      *
298      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getLastActivated(javax.jcr.Node)}
299      */
300     public Calendar getLastActionDate() {
301         return getDateProperty(LAST_ACTION);
302     }
303 
304     /**
305      * Part of metadata, adds modification date of the current node.
306      *
307      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#update(javax.jcr.Node)}
308      */
309     public void setModificationDate() {
310         Calendar value = new GregorianCalendar(TimeZone.getDefault());
311         setProperty(LAST_MODIFIED, value);
312     }
313 
314     /**
315      * Get last modified date of the node to which this meta data belongs or creation date in case content was not
316      * modified since.
317      *
318      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#getLastModified(Node)}
319      */
320     public Calendar getModificationDate() {
321         Calendar modDate = getDateProperty(LAST_MODIFIED);
322         if (modDate == null) {
323             modDate = getCreationDate();
324         }
325         return modDate;
326     }
327 
328     /**
329      * Part of metadata, last known author of this node.
330      *
331      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#getLastModifiedBy(javax.jcr.Node)}
332      */
333     public String getAuthorId() {
334         return getStringProperty(AUTHOR_ID);
335     }
336 
337     /**
338      * Part of metadata, current logged-in author who did some action on this page.
339      *
340      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#update(javax.jcr.Node, String, java.util.Calendar)}
341      */
342     public void setAuthorId(String value) {
343         setProperty(AUTHOR_ID, value);
344     }
345 
346     /**
347      * Part of metadata, last known activator of this node.
348      *
349      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getLastActivatedBy(javax.jcr.Node)}
350      */
351     public String getActivatorId() {
352         return getStringProperty(ACTIVATOR_ID);
353     }
354 
355     /**
356      * Part of metadata, current logged-in author who last activated this page.
357      *
358      * @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.
359      */
360     public void setActivatorId(String value) {
361         setProperty(ACTIVATOR_ID, value);
362     }
363 
364     /**
365      * Part of metadata, template which will be used to render content of this node.
366      *
367      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#getTemplate(javax.jcr.Node)}
368      */
369     public String getTemplate() {
370         return getStringProperty(TEMPLATE);
371     }
372 
373     /**
374      * Part of metadata, template which will be used to render content of this node.
375      *
376      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#set(javax.jcr.Node, String)}
377      */
378     public void setTemplate(String value) {
379         setProperty(TEMPLATE, value);
380     }
381 
382     public void setProperty(String name, String value) {
383         setJCRProperty(name, value);
384     }
385 
386     public void setProperty(String name, long value) {
387         setJCRProperty(name, value);
388     }
389 
390     public void setProperty(String name, double value) {
391         setJCRProperty(name, value);
392     }
393 
394     public void setProperty(String name, boolean value) {
395         setJCRProperty(name, value);
396     }
397 
398     public void setProperty(String name, Calendar value) {
399         setJCRProperty(name, value);
400     }
401 
402     private void setJCRProperty(String name, Object value) {
403         final String propName = this.getInternalPropertyName(name);
404         try {
405             PropertyUtil.setProperty(node, propName, value);
406         } catch (RepositoryException re) {
407             log.error(re.getMessage(), re);
408         }
409     }
410 
411     public boolean getBooleanProperty(String name) {
412         try {
413             final Property property = getJCRProperty(name);
414             if (property != null) {
415                 return property.getBoolean();
416             }
417         } catch (RepositoryException re) {
418             log.error(re.getMessage(), re);
419         }
420         return false;
421     }
422 
423     public double getDoubleProperty(String name) {
424         try {
425             final Property property = getJCRProperty(name);
426             if (property != null) {
427                 return property.getDouble();
428             }
429         } catch (RepositoryException re) {
430             log.error(re.getMessage(), re);
431         }
432         return 0d;
433     }
434 
435     public long getLongProperty(String name) {
436         try {
437             final Property property = getJCRProperty(name);
438             if (property != null) {
439                 return property.getLong();
440             }
441         } catch (RepositoryException re) {
442             log.error(re.getMessage(), re);
443         }
444         return 0L;
445     }
446 
447     public String getStringProperty(String name) {
448         try {
449             final Property property = getJCRProperty(name);
450             if (property != null) {
451                 return property.getString();
452             }
453         } catch (RepositoryException re) {
454             log.error(re.getMessage(), re);
455         }
456         return StringUtils.EMPTY;
457     }
458 
459     public Calendar getDateProperty(String name) {
460         try {
461             final Property property = getJCRProperty(name);
462             if (property != null) {
463                 return property.getDate();
464             }
465         } catch (RepositoryException re) {
466             log.error(re.getMessage(), re);
467         }
468         return null;
469     }
470 
471     /**
472      * remove specified property.
473      *
474      * @param name
475      *            of the property to be removed
476      * @throws PathNotFoundException
477      *             if property does not exist
478      * @throws RepositoryException
479      *             if unable to remove
480      */
481     public void removeProperty(String name) throws PathNotFoundException, RepositoryException {
482         this.node.getProperty(this.getInternalPropertyName(name)).remove();
483     }
484 
485     private Property getJCRProperty(String name) throws RepositoryException {
486         final String propName = this.getInternalPropertyName(name);
487         try {
488             return node.getProperty(propName);
489         } catch (PathNotFoundException re) {
490             log.debug("PathNotFoundException for property [{}] in node {}", propName, node);
491         }
492         return null;
493     }
494 }