View Javadoc

1   /**
2    * This file Copyright (c) 2003-2011 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.beans.config.ContentRepository;
37  import info.magnolia.cms.security.AccessDeniedException;
38  import info.magnolia.cms.security.AccessManager;
39  import info.magnolia.cms.security.Permission;
40  import org.apache.commons.lang.StringUtils;
41  import org.apache.commons.lang.builder.ToStringBuilder;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import javax.jcr.Node;
46  import javax.jcr.PathNotFoundException;
47  import javax.jcr.PropertyIterator;
48  import javax.jcr.RepositoryException;
49  import javax.jcr.Property;
50  
51  import java.util.Calendar;
52  import java.util.GregorianCalendar;
53  import java.util.TimeZone;
54  
55  
56  /**
57   * Meta data of a content like creation date, modification date, assigned template, ...
58   */
59  public class MetaData {
60      private static final Logger log = LoggerFactory.getLogger(MetaData.class);
61  
62      /**
63       * Top level atoms viewed as metadata of the specified content these must be set by the authoring system itself, but
64       * could be changed via custom templates if necessary.
65       */
66      public static final String TITLE = "title"; //$NON-NLS-1$
67  
68      public static final String CREATION_DATE = "creationdate"; //$NON-NLS-1$
69  
70      public static final String LAST_MODIFIED = "lastmodified"; //$NON-NLS-1$
71  
72      public static final String LAST_ACTION = "lastaction"; //$NON-NLS-1$
73  
74      public static final String AUTHOR_ID = "authorid"; //$NON-NLS-1$
75  
76      public static final String ACTIVATOR_ID = "activatorid"; //$NON-NLS-1$
77  
78      public static final String TEMPLATE = "template"; //$NON-NLS-1$
79  
80      public static final String TEMPLATE_TYPE = "templatetype"; //$NON-NLS-1$
81  
82      public static final String ACTIVATED = "activated"; //$NON-NLS-1$
83  
84      public static final String DEFAULT_META_NODE = "MetaData"; //$NON-NLS-1$
85  
86      public static final int ACTIVATION_STATUS_NOT_ACTIVATED = 0;
87  
88      public static final int ACTIVATION_STATUS_MODIFIED = 1;
89  
90      public static final int ACTIVATION_STATUS_ACTIVATED = 2;
91  
92      /**
93       * meta data node.
94       */
95      private Node node;
96  
97      private AccessManager accessManager;
98  
99      /**
100      * Package private constructor.
101      * @param workingNode current <code>Node</code> on which <code>MetaData</code> is requested
102      */
103     protected MetaData(Node workingNode, AccessManager manager) {
104         try {
105             this.node = workingNode.getNode(DEFAULT_META_NODE);
106         } catch (PathNotFoundException e) {
107             try {
108                 log.debug("{} does not support MetaData, check node type definition of {}", workingNode.getPath(), workingNode.getPrimaryNodeType().getName());
109             } catch (RepositoryException re) {
110                 // should never come here
111             }
112         } catch (RepositoryException re) {
113             log.error(re.getMessage(), re);
114         }
115         this.accessManager = manager;
116     }
117 
118     protected MetaData() {
119     }
120 
121     public String getHandle() throws RepositoryException {
122         return this.node.getPath();
123     }
124 
125     private void allowUpdate() throws AccessDeniedException {
126         // if node is null, MetaData has not been created and allowUpdate can abort silently
127         if (node == null) {
128             return;
129         }
130         try {
131             Access.isGranted(this.accessManager, Path.getAbsolutePath(this.node.getPath()), Permission.WRITE);
132         }
133         catch (RepositoryException re) {
134             log.error(re.getMessage(), re);
135             throw new AccessDeniedException(re.getMessage());
136         }
137     }
138 
139     /**
140      * Get all meta data properties.
141      * @return property iterator
142      * @deprecated since 4.0 - not used.
143      */
144     @Deprecated
145     public PropertyIterator getProperties() {
146         if (node == null) {
147             return null;
148         }
149         try {
150             return this.node.getProperties();
151         }
152         catch (RepositoryException re) {
153             log.error(re.getMessage(), re);
154         }
155         return null;
156     }
157 
158     /**
159      * Part of metadata, same as name of actual storage node. This value is unique at the hierarchy level context.
160      * @return String value of the requested metadata
161      */
162     public String getLabel() {
163         try {
164             return this.node.getName();
165         }
166         catch (NullPointerException e) {
167             if (log.isDebugEnabled()) {
168                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
169             }
170         }
171         catch (RepositoryException e) {
172             log.error(e.getMessage(), e);
173         }
174         return StringUtils.EMPTY;
175     }
176 
177     /**
178      * get property name with the prefix.
179      * @param name
180      * @return name with namespace prefix
181      */
182     private String getInternalPropertyName(String name) {
183         if (StringUtils.indexOf(name, ContentRepository.NAMESPACE_PREFIX + ":") != 0) {
184             return ContentRepository.NAMESPACE_PREFIX + ":" + name;
185         }
186         return name;
187     }
188 
189     /**
190      * Part of metadata , could be used as html header.
191      * @return String value of the requested metadata
192      */
193     public String getTitle() {
194         return getStringProperty(this.getInternalPropertyName(TITLE));
195     }
196 
197     /**
198      * Part of metadata, could be used as html header.
199      * @param value
200      */
201     public void setTitle(String value) throws AccessDeniedException {
202         allowUpdate();
203         setProperty(this.getInternalPropertyName(TITLE), value);
204     }
205 
206     /**
207      * Part of metadata, adds creation date of the current node.
208      */
209     public void setCreationDate() throws AccessDeniedException {
210         allowUpdate();
211         Calendar value = new GregorianCalendar(TimeZone.getDefault());
212         setProperty(this.getInternalPropertyName(CREATION_DATE), value);
213     }
214 
215     /**
216      * Part of metadata, get creation date of the current node.
217      * @return Calendar
218      */
219     public Calendar getCreationDate() {
220         return this.getDateProperty(this.getInternalPropertyName(CREATION_DATE));
221     }
222 
223     /**
224      * Part of metadata, adds activated status of the current node.
225      */
226     public void setActivated() throws AccessDeniedException {
227         allowUpdate();
228         setProperty(this.getInternalPropertyName(ACTIVATED), true);
229     }
230 
231     /**
232      * Part of metadata, adds activated status of the current node.
233      */
234     public void setUnActivated() throws AccessDeniedException {
235         allowUpdate();
236         setProperty(this.getInternalPropertyName(ACTIVATED), false);
237     }
238 
239     /**
240      * Part of metadata, get last activated status of the current node.
241      * @return Calendar
242      */
243     public boolean getIsActivated() {
244         return getBooleanProperty(this.getInternalPropertyName(ACTIVATED));
245     }
246 
247     /**
248      * Returns one of the ACTIVATION_STATUS_* constants.
249      */
250     public int getActivationStatus(){
251         if (getIsActivated()) {
252             if (getModificationDate() != null && getModificationDate().after(getLastActionDate())) {
253                 // node has been modified after last activation
254                 return ACTIVATION_STATUS_MODIFIED;
255             }
256             else {
257                 // activated and not modified ever since
258                 return ACTIVATION_STATUS_ACTIVATED;
259             }
260         }
261         else {
262             // never activated or deactivated
263             return ACTIVATION_STATUS_NOT_ACTIVATED;
264         }
265     }
266 
267     /**
268      * Part of metadata, adds activated date of the current node.
269      */
270     public void setLastActivationActionDate() throws AccessDeniedException {
271         allowUpdate();
272         Calendar value = new GregorianCalendar(TimeZone.getDefault());
273         setProperty(this.getInternalPropertyName(LAST_ACTION), value);
274     }
275 
276     /**
277      * Part of metadata, get last activated/de- date of the current node.
278      * @return Calendar
279      */
280     public Calendar getLastActionDate() {
281         return getDateProperty(this.getInternalPropertyName(LAST_ACTION));
282     }
283 
284     /**
285      * Part of metadata, adds modification date of the current node.
286      */
287     public void setModificationDate() throws AccessDeniedException {
288         allowUpdate();
289         Calendar value = new GregorianCalendar(TimeZone.getDefault());
290         setProperty(this.getInternalPropertyName(LAST_MODIFIED), value);
291     }
292 
293     /**
294      * Get last modified date of the node to which this meta data belongs or creation date in case content was not modified since.
295      * @return Calendar when last modification date can't be found.
296      */
297     public Calendar getModificationDate() {
298         Calendar modDate = getDateProperty(this.getInternalPropertyName(LAST_MODIFIED));
299         if (modDate == null) {
300             modDate = getCreationDate();
301         }
302         return modDate;
303     }
304 
305     /**
306      * Part of metadata, last known author of this node.
307      * @return String value of the requested metadata
308      */
309     public String getAuthorId() {
310         return getStringProperty(this.getInternalPropertyName(AUTHOR_ID));
311     }
312 
313     /**
314      * Part of metadata, current logged-in author who did some action on this page.
315      * @param value
316      */
317     public void setAuthorId(String value) throws AccessDeniedException {
318         allowUpdate();
319         setProperty(this.getInternalPropertyName(AUTHOR_ID), value);
320     }
321 
322     /**
323      * Part of metadata, last known activator of this node.
324      * @return String value of the requested metadata
325      */
326     public String getActivatorId() {
327         return getStringProperty(this.getInternalPropertyName(ACTIVATOR_ID));
328     }
329 
330     /**
331      * Part of metadata, current logged-in author who last activated this page.
332      * @param value
333      */
334     public void setActivatorId(String value) throws AccessDeniedException {
335         allowUpdate();
336         setProperty(this.getInternalPropertyName(ACTIVATOR_ID), value);
337     }
338 
339     /**
340      * Part of metadata, template which will be used to render content of this node.
341      * @return String value of the requested metadata
342      */
343     public String getTemplate() {
344         return getStringProperty(this.getInternalPropertyName(TEMPLATE));
345     }
346 
347     /**
348      * Part of metadata, template which will be used to render content of this node.
349      * @param value
350      */
351     public void setTemplate(String value) throws AccessDeniedException {
352         allowUpdate();
353         setProperty(this.getInternalPropertyName(TEMPLATE), value);
354     }
355 
356     /**
357      * Part of metadata, template type : JSP - Servlet - _xxx_.
358      * @param value
359      * @deprecated since 4.0 - not used - template type is determined by template definition
360      */
361     @Deprecated
362     public void setTemplateType(String value) throws AccessDeniedException {
363         allowUpdate();
364         setProperty(this.getInternalPropertyName(TEMPLATE_TYPE), value);
365     }
366 
367     public void setProperty(String name, String value) throws AccessDeniedException {
368         allowUpdate();
369         name = this.getInternalPropertyName(name);
370         try {
371             this.node.getProperty(name).setValue(value);
372         }
373         catch (PathNotFoundException e) {
374             try {
375                 this.node.setProperty(name, value);
376             }
377             catch (RepositoryException re) {
378                 log.error(re.getMessage(), re);
379             }
380         }
381         catch (RepositoryException re) {
382             throw new AccessDeniedException(re.getMessage(), re);
383         }
384         catch (NullPointerException e) {
385             log.debug("MetaData has not been created or this node does not support MetaData. Cannot set property {}", name);
386         }
387     }
388 
389     public void setProperty(String name, long value) throws AccessDeniedException {
390         allowUpdate();
391         name = this.getInternalPropertyName(name);
392         try {
393             this.node.getProperty(name).setValue(value);
394         }
395         catch (PathNotFoundException e) {
396             try {
397                 this.node.setProperty(name, value);
398             }
399             catch (RepositoryException re) {
400                 log.error(re.getMessage(), re);
401             }
402         }
403         catch (RepositoryException re) {
404             log.error(re.getMessage(), re);
405             throw new AccessDeniedException(re.getMessage());
406         }
407         catch (NullPointerException e) {
408             if (log.isDebugEnabled()) {
409                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
410                 log.debug("cannot set property - " + name); //$NON-NLS-1$
411             }
412         }
413     }
414 
415     public void setProperty(String name, double value) throws AccessDeniedException {
416         allowUpdate();
417         name = this.getInternalPropertyName(name);
418         try {
419             this.node.getProperty(name).setValue(value);
420         }
421         catch (PathNotFoundException e) {
422             try {
423                 this.node.setProperty(name, value);
424             }
425             catch (RepositoryException re) {
426                 log.error(re.getMessage(), re);
427             }
428         }
429         catch (RepositoryException re) {
430             log.error(re.getMessage(), re);
431             throw new AccessDeniedException(re.getMessage());
432         }
433         catch (NullPointerException e) {
434             if (log.isDebugEnabled()) {
435                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
436                 log.debug("cannot set property - " + name); //$NON-NLS-1$
437             }
438         }
439     }
440 
441     public void setProperty(String name, boolean value) throws AccessDeniedException {
442         allowUpdate();
443         name = this.getInternalPropertyName(name);
444         try {
445             this.node.getProperty(name).setValue(value);
446         }
447         catch (PathNotFoundException e) {
448             try {
449                 this.node.setProperty(name, value);
450             }
451             catch (RepositoryException re) {
452                 log.error(re.getMessage(), re);
453             }
454         }
455         catch (RepositoryException re) {
456             log.error(re.getMessage(), re);
457             throw new AccessDeniedException(re.getMessage());
458         }
459         catch (NullPointerException e) {
460             if (log.isDebugEnabled()) {
461                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
462                 log.debug("cannot set property - " + name); //$NON-NLS-1$
463             }
464         }
465     }
466 
467     public void setProperty(String name, Calendar value) throws AccessDeniedException {
468         allowUpdate();
469         name = this.getInternalPropertyName(name);
470         try {
471             this.node.getProperty(name).setValue(value);
472         }
473         catch (PathNotFoundException e) {
474             try {
475                 this.node.setProperty(name, value);
476             }
477             catch (RepositoryException re) {
478                 log.error(re.getMessage(), re);
479             }
480         }
481         catch (RepositoryException re) {
482             log.error(re.getMessage(), re);
483             throw new AccessDeniedException(re.getMessage());
484         }
485         catch (NullPointerException e) {
486             log.debug("MetaData has not been created or this node does not support MetaData. Cannot set property {}", name);
487         }
488     }
489 
490     /**
491      * Gets date property or null if such property doesn't exist. Do not use this method for checking existence of the property.
492      */
493     public Calendar getDateProperty(String name) {
494         name = this.getInternalPropertyName(name);
495         try {
496             final Property property = this.node.getProperty(name);
497             return property.getDate();
498         }
499         catch (PathNotFoundException re) {
500             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$
501         }
502         catch (RepositoryException re) {
503             log.error(re.getMessage(), re);
504         }
505         catch (NullPointerException e) {
506             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
507         }
508         return null;
509     }
510 
511     public boolean getBooleanProperty(String name) {
512         name = this.getInternalPropertyName(name);
513         try {
514             final Property property = this.node.getProperty(name);
515             return property.getBoolean();
516         }
517         catch (PathNotFoundException re) {
518             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$
519         }
520         catch (RepositoryException re) {
521             log.error(re.getMessage(), re);
522         }
523         catch (NullPointerException e) {
524             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
525         }
526         return false;
527     }
528 
529     public double getDoubleProperty(String name) {
530         name = this.getInternalPropertyName(name);
531         try {
532             final Property property = this.node.getProperty(name);
533             return property.getDouble();
534         }
535         catch (PathNotFoundException re) {
536             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$
537         }
538         catch (RepositoryException re) {
539             log.error(re.getMessage(), re);
540         }
541         catch (NullPointerException e) {
542             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
543         }
544         return 0d;
545     }
546 
547     public long getLongProperty(String name) {
548         name = this.getInternalPropertyName(name);
549         try {
550             final Property property = this.node.getProperty(name);
551             return property.getLong();
552         }
553         catch (PathNotFoundException re) {
554             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$
555         }
556         catch (RepositoryException re) {
557             log.error(re.getMessage(), re);
558         }
559         catch (NullPointerException e) {
560             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
561         }
562         return 0L;
563     }
564 
565     /**
566      * Returns a String property. If the property does not exist, this will return an empty String.
567      * @param name
568      * @return the property value, never null
569      */
570     public String getStringProperty(String name) {
571         name = this.getInternalPropertyName(name);
572         try {
573             final Property property = this.node.getProperty(name);
574             return property.getString();
575         }
576         catch (PathNotFoundException re) {
577             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$
578         }
579         catch (RepositoryException re) {
580             log.error(re.getMessage(), re);
581         }
582         catch (NullPointerException e) {
583             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
584         }
585         return StringUtils.EMPTY;
586     }
587 
588 
589     /**
590      * remove specified property.
591      * @param name of the property to be removed
592      * @throws PathNotFoundException if property does not exist
593      * @throws RepositoryException if unable to remove
594      */
595     public void removeProperty(String name) throws PathNotFoundException, RepositoryException {
596         this.node.getProperty(this.getInternalPropertyName(name)).remove();
597     }
598 
599     /**
600      * check if property exists.
601      * @param name
602      * @return true if the specified property exist
603      *
604      * @deprecated since 4.0 - not used
605      */
606     @Deprecated
607     public boolean hasProperty(String name) {
608         try {
609             return this.node.hasProperty(this.getInternalPropertyName(name));
610         }
611         catch (RepositoryException re) {
612             log.error(re.getMessage(), re);
613         }
614         return false;
615     }
616 
617     @Override
618     public String toString() {
619         return new ToStringBuilder(this).append("title", this.getTitle()) //$NON-NLS-1$
620         .append("template", this.getTemplate()) //$NON-NLS-1$
621         .append("authorId", this.getAuthorId()) //$NON-NLS-1$
622         .append("label", this.getLabel()) //$NON-NLS-1$
623         .append("activatorId", this.getActivatorId()) //$NON-NLS-1$
624         .append("isActivated", this.getIsActivated()) //$NON-NLS-1$
625         .append("creationDate", this.getCreationDate()) //$NON-NLS-1$
626         .append("lastActionDate", this.getLastActionDate()) //$NON-NLS-1$
627         .append("modificationDate", this.getModificationDate()) //$NON-NLS-1$
628         .toString();
629     }
630 
631 }