View Javadoc
1   /**
2    * This file Copyright (c) 2003-2018 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.lang3.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  @Deprecated
66  public class MetaData {
67      private static final Logger log = LoggerFactory.getLogger(MetaData.class);
68  
69      /**
70       * Top level atoms viewed as metadata of the specified content these must be set by the authoring system itself, but
71       * could be changed via custom templates if necessary.
72       */
73  
74      /**
75       * @deprecated since 5.0 - no longer supported
76       */
77      public static final String TITLE = "title";
78  
79      /**
80       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#CREATED} instead
81       */
82      public static final String CREATION_DATE = "creationdate";
83  
84      /**
85       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#LAST_MODIFIED} instead
86       */
87      public static final String LAST_MODIFIED = "lastmodified";
88  
89      /**
90       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#LAST_ACTIVATED} instead
91       */
92      public static final String LAST_ACTION = "lastaction";
93  
94      /**
95       * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#LAST_MODIFIED_BY} instead
96       */
97      public static final String AUTHOR_ID = "authorid";
98  
99      /**
100      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#LAST_ACTIVATED_BY} instead
101      */
102     public static final String ACTIVATOR_ID = "activatorid";
103 
104     /**
105      * Template assigned to the node.
106      *
107      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#TEMPLATE} instead
108      */
109     public static final String TEMPLATE = "template";
110 
111     /**
112      * @deprecated since 5.0 - no longer supported
113      */
114     public static final String TEMPLATE_TYPE = "templatetype";
115 
116     /**
117      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS} instead
118      */
119     public static final String ACTIVATED = "activated";
120 
121     /**
122      * Name of the node hosting the MetaData.
123      *
124      * @deprecated since 5.0 - there's no longer such a subnode
125      */
126     public static final String DEFAULT_META_NODE = "MetaData";
127 
128     /**
129      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_NOT_ACTIVATED} instead
130      */
131     public static final int ACTIVATION_STATUS_NOT_ACTIVATED = NodeTypes.Activatable.ACTIVATION_STATUS_NOT_ACTIVATED;
132 
133     /**
134      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_MODIFIED} instead
135      */
136     public static final int ACTIVATION_STATUS_MODIFIED = NodeTypes.Activatable.ACTIVATION_STATUS_MODIFIED;
137 
138     /**
139      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#ACTIVATION_STATUS_ACTIVATED} instead
140      */
141     public static final int ACTIVATION_STATUS_ACTIVATED = NodeTypes.Activatable.ACTIVATION_STATUS_ACTIVATED;
142 
143     /**
144      * Since 5.0 this is the working node itself.
145      */
146     private Node node;
147 
148     /**
149      * @param workingNode current <code>Node</code> on which <code>MetaData</code> is requested
150      * @param ignoredAccessManager no longer required hence use other constructor.
151      * @deprecated since 4.5 use MetaData(Node) instead.
152      */
153     protected MetaData(Node workingNode, AccessManager ignoredAccessManager) {
154         this(workingNode);
155     }
156 
157     /**
158      * @param workingNode current <code>Node</code> on which <code>MetaData</code> is requested
159      */
160     public MetaData(Node workingNode) {
161         this.node = workingNode;
162     }
163 
164     /**
165      * Maps property names from the names used when we had a MetaData sub node to their replacements on mixins on the
166      * working node itself.
167      */
168     private static Map<String, String> propertyMappings = new ConcurrentHashMap<String, String>();
169 
170     static {
171         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATION_DATE, NodeTypes.Created.CREATED);
172         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + LAST_MODIFIED, NodeTypes.LastModified.LAST_MODIFIED);
173         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + LAST_ACTION, NodeTypes.Activatable.LAST_ACTIVATED);
174         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + AUTHOR_ID, NodeTypes.LastModified.LAST_MODIFIED_BY);
175         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + ACTIVATOR_ID, NodeTypes.Activatable.LAST_ACTIVATED_BY);
176         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + TEMPLATE, NodeTypes.Renderable.TEMPLATE);
177         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":" + ACTIVATED, NodeTypes.Activatable.ACTIVATION_STATUS);
178         propertyMappings.put(RepositoryConstants.NAMESPACE_PREFIX + ":comment", NodeTypes.Versionable.COMMENT);
179     }
180 
181     /**
182      * Returns the property name to use including its prefix.
183      *
184      * @return name with namespace prefix
185      */
186     private String getInternalPropertyName(String name) {
187         if (StringUtils.indexOf(name, ":") < 0) {
188             name = RepositoryConstants.NAMESPACE_PREFIX + ":" + name;
189         }
190 
191         String newName = propertyMappings.get(name);
192 
193         if (newName == null) {
194             throw new IllegalArgumentException("Unsupported meta data property: " + name);
195         }
196 
197         return newName;
198     }
199 
200     /**
201      * @return value of property TITLE if it's around on working node
202      * @deprecated since 5.0 - only for backwards compatibility.
203      */
204     public String getTitle() {
205         return getStringProperty(TITLE);
206     }
207 
208     /**
209      * Will set value of property TITLE on working node.
210      *
211      * @deprecated since 5.0 - only for backwards compatibility.
212      */
213     public void setTitle(String value) {
214         setProperty(TITLE, value);
215     }
216 
217     /**
218      * Part of metadata, adds creation date of the current node.
219      *
220      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#set(Node)}
221      */
222     public void setCreationDate() {
223         Calendar value = new GregorianCalendar(TimeZone.getDefault());
224         setProperty(CREATION_DATE, value);
225     }
226 
227     /**
228      * Part of metadata, get creation date of the current node.
229      *
230      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Created#getCreated(Node)}
231      */
232     public Calendar getCreationDate() {
233         return this.getDateProperty(CREATION_DATE);
234     }
235 
236     /**
237      * Part of metadata, adds activated status of the current node.
238      *
239      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
240      */
241     public void setActivated() {
242         setProperty(ACTIVATED, true);
243     }
244 
245     /**
246      * Part of metadata, adds activated status of the current node.
247      *
248      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
249      */
250     public void setUnActivated() {
251         setProperty(ACTIVATED, false);
252     }
253 
254     /**
255      * Part of metadata, get last activated status of the current node.
256      *
257      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#isActivated(javax.jcr.Node)}
258      */
259     public boolean getIsActivated() {
260         return getBooleanProperty(ACTIVATED);
261     }
262 
263     /**
264      * Returns one of the ACTIVATION_STATUS_* constants.
265      *
266      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getActivationStatus(javax.jcr.Node)}
267      */
268     public int getActivationStatus() {
269         if (getIsActivated()) {
270             if (getModificationDate() != null && getModificationDate().after(getLastActionDate())) {
271                 // node has been modified after last activation
272                 return ACTIVATION_STATUS_MODIFIED;
273             }
274             // activated and not modified ever since
275             return ACTIVATION_STATUS_ACTIVATED;
276         }
277         // never activated or deactivated
278         return ACTIVATION_STATUS_NOT_ACTIVATED;
279     }
280 
281     /**
282      * Part of metadata, adds activated date of the current node.
283      *
284      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#update(javax.jcr.Node, String, boolean)}
285      */
286     public void setLastActivationActionDate() {
287         Calendar value = new GregorianCalendar(TimeZone.getDefault());
288         setProperty(LAST_ACTION, value);
289     }
290 
291     /**
292      * Part of metadata, get last activated/de- date of the current node.
293      *
294      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getLastActivated(javax.jcr.Node)}
295      */
296     public Calendar getLastActionDate() {
297         return getDateProperty(LAST_ACTION);
298     }
299 
300     /**
301      * Part of metadata, adds modification date of the current node.
302      *
303      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#update(javax.jcr.Node)}
304      */
305     public void setModificationDate() {
306         Calendar value = new GregorianCalendar(TimeZone.getDefault());
307         setProperty(LAST_MODIFIED, value);
308     }
309 
310     /**
311      * Get last modified date of the node to which this meta data belongs or creation date in case content was not
312      * modified since.
313      *
314      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#getLastModified(Node)}
315      */
316     public Calendar getModificationDate() {
317         Calendar modDate = getDateProperty(LAST_MODIFIED);
318         if (modDate == null) {
319             modDate = getCreationDate();
320         }
321         return modDate;
322     }
323 
324     /**
325      * Part of metadata, last known author of this node.
326      *
327      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#getLastModifiedBy(javax.jcr.Node)}
328      */
329     public String getAuthorId() {
330         return getStringProperty(AUTHOR_ID);
331     }
332 
333     /**
334      * Part of metadata, current logged-in author who did some action on this page.
335      *
336      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.LastModified#update(javax.jcr.Node, String, java.util.Calendar)}
337      */
338     public void setAuthorId(String value) {
339         setProperty(AUTHOR_ID, value);
340     }
341 
342     /**
343      * Part of metadata, last known activator of this node.
344      *
345      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Activatable#getLastActivatedBy(javax.jcr.Node)}
346      */
347     public String getActivatorId() {
348         return getStringProperty(ACTIVATOR_ID);
349     }
350 
351     /**
352      * Part of metadata, current logged-in author who last activated this page.
353      *
354      * @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.
355      */
356     public void setActivatorId(String value) {
357         setProperty(ACTIVATOR_ID, value);
358     }
359 
360     /**
361      * Part of metadata, template which will be used to render content of this node.
362      *
363      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#getTemplate(javax.jcr.Node)}
364      */
365     public String getTemplate() {
366         return getStringProperty(TEMPLATE);
367     }
368 
369     /**
370      * Part of metadata, template which will be used to render content of this node.
371      *
372      * @deprecated since 5.0 - use {@link info.magnolia.jcr.util.NodeTypes.Renderable#set(javax.jcr.Node, String)}
373      */
374     public void setTemplate(String value) {
375         setProperty(TEMPLATE, value);
376     }
377 
378     public void setProperty(String name, String value) {
379         setJCRProperty(name, value);
380     }
381 
382     public void setProperty(String name, long value) {
383         setJCRProperty(name, value);
384     }
385 
386     public void setProperty(String name, double value) {
387         setJCRProperty(name, value);
388     }
389 
390     public void setProperty(String name, boolean value) {
391         setJCRProperty(name, value);
392     }
393 
394     public void setProperty(String name, Calendar value) {
395         setJCRProperty(name, value);
396     }
397 
398     private void setJCRProperty(String name, Object value) {
399         final String propName = this.getInternalPropertyName(name);
400         try {
401             PropertyUtil.setProperty(node, propName, value);
402         } catch (RepositoryException re) {
403             log.error(re.getMessage(), re);
404         }
405     }
406 
407     public boolean getBooleanProperty(String name) {
408         try {
409             final Property property = getJCRProperty(name);
410             if (property != null) {
411                 return property.getBoolean();
412             }
413         } catch (RepositoryException re) {
414             log.error(re.getMessage(), re);
415         }
416         return false;
417     }
418 
419     public double getDoubleProperty(String name) {
420         try {
421             final Property property = getJCRProperty(name);
422             if (property != null) {
423                 return property.getDouble();
424             }
425         } catch (RepositoryException re) {
426             log.error(re.getMessage(), re);
427         }
428         return 0d;
429     }
430 
431     public long getLongProperty(String name) {
432         try {
433             final Property property = getJCRProperty(name);
434             if (property != null) {
435                 return property.getLong();
436             }
437         } catch (RepositoryException re) {
438             log.error(re.getMessage(), re);
439         }
440         return 0L;
441     }
442 
443     public String getStringProperty(String name) {
444         try {
445             final Property property = getJCRProperty(name);
446             if (property != null) {
447                 return property.getString();
448             }
449         } catch (RepositoryException re) {
450             log.error(re.getMessage(), re);
451         }
452         return StringUtils.EMPTY;
453     }
454 
455     public Calendar getDateProperty(String name) {
456         try {
457             final Property property = getJCRProperty(name);
458             if (property != null) {
459                 return property.getDate();
460             }
461         } catch (RepositoryException re) {
462             log.error(re.getMessage(), re);
463         }
464         return null;
465     }
466 
467     /**
468      * remove specified property.
469      *
470      * @param name of the property to be removed
471      * @throws PathNotFoundException if property does not exist
472      * @throws RepositoryException if unable to remove
473      */
474     public void removeProperty(String name) throws PathNotFoundException, RepositoryException {
475         this.node.getProperty(this.getInternalPropertyName(name)).remove();
476     }
477 
478     private Property getJCRProperty(String name) throws RepositoryException {
479         final String propName = this.getInternalPropertyName(name);
480         try {
481             return node.getProperty(propName);
482         } catch (PathNotFoundException re) {
483             log.debug("PathNotFoundException for property [{}] in node {}", propName, node);
484         }
485         return null;
486     }
487 }