View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 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     public PropertyIterator getProperties() {
145         if (node == null) {
146             return null;
147         }
148         try {
149             return this.node.getProperties();
150         }
151         catch (RepositoryException re) {
152             log.error(re.getMessage(), re);
153         }
154         return null;
155     }
156 
157     /**
158      * Part of metadata, same as name of actual storage node. This value is unique at the hierarchy level context.
159      * @return String value of the requested metadata
160      */
161     public String getLabel() {
162         try {
163             return this.node.getName();
164         }
165         catch (NullPointerException e) {
166             if (log.isDebugEnabled()) {
167                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
168             }
169         }
170         catch (RepositoryException e) {
171             log.error(e.getMessage(), e);
172         }
173         return StringUtils.EMPTY;
174     }
175 
176     /**
177      * get property name with the prefix.
178      * @param name
179      * @return name with namespace prefix
180      */
181     private String getInternalPropertyName(String name) {
182         if (StringUtils.indexOf(name, ContentRepository.NAMESPACE_PREFIX + ":") != 0) {
183             return ContentRepository.NAMESPACE_PREFIX + ":" + name;
184         }
185         return name;
186     }
187 
188     /**
189      * Part of metadata , could be used as html header.
190      * @return String value of the requested metadata
191      */
192     public String getTitle() {
193         return getStringProperty(this.getInternalPropertyName(TITLE));
194     }
195 
196     /**
197      * Part of metadata, could be used as html header.
198      * @param value
199      */
200     public void setTitle(String value) throws AccessDeniedException {
201         allowUpdate();
202         setProperty(this.getInternalPropertyName(TITLE), value);
203     }
204 
205     /**
206      * Part of metadata, adds creation date of the current node.
207      */
208     public void setCreationDate() throws AccessDeniedException {
209         allowUpdate();
210         Calendar value = new GregorianCalendar(TimeZone.getDefault());
211         setProperty(this.getInternalPropertyName(CREATION_DATE), value);
212     }
213 
214     /**
215      * Part of metadata, get creation date of the current node.
216      * @return Calendar
217      */
218     public Calendar getCreationDate() {
219         return this.getDateProperty(this.getInternalPropertyName(CREATION_DATE));
220     }
221 
222     /**
223      * Part of metadata, adds activated status of the current node.
224      */
225     public void setActivated() throws AccessDeniedException {
226         allowUpdate();
227         setProperty(this.getInternalPropertyName(ACTIVATED), true);
228     }
229 
230     /**
231      * Part of metadata, adds activated status of the current node.
232      */
233     public void setUnActivated() throws AccessDeniedException {
234         allowUpdate();
235         setProperty(this.getInternalPropertyName(ACTIVATED), false);
236     }
237 
238     /**
239      * Part of metadata, get last activated status of the current node.
240      * @return Calendar
241      */
242     public boolean getIsActivated() {
243         return getBooleanProperty(this.getInternalPropertyName(ACTIVATED));
244     }
245 
246     /**
247      * Returns one of the ACTIVATION_STATUS_* constants.
248      */
249     public int getActivationStatus(){
250         if (getIsActivated()) {
251             if (getModificationDate() != null && getModificationDate().after(getLastActionDate())) {
252                 // node has been modified after last activation
253                 return ACTIVATION_STATUS_MODIFIED;
254             }
255             else {
256                 // activated and not modified ever since
257                 return ACTIVATION_STATUS_ACTIVATED;
258             }
259         }
260         else {
261             // never activated or deactivated
262             return ACTIVATION_STATUS_NOT_ACTIVATED;
263         }
264     }
265 
266     /**
267      * Part of metadata, adds activated date of the current node.
268      */
269     public void setLastActivationActionDate() throws AccessDeniedException {
270         allowUpdate();
271         Calendar value = new GregorianCalendar(TimeZone.getDefault());
272         setProperty(this.getInternalPropertyName(LAST_ACTION), value);
273     }
274 
275     /**
276      * Part of metadata, get last activated/de- date of the current node.
277      * @return Calendar
278      */
279     public Calendar getLastActionDate() {
280         return getDateProperty(this.getInternalPropertyName(LAST_ACTION));
281     }
282 
283     /**
284      * Part of metadata, adds modification date of the current node.
285      */
286     public void setModificationDate() throws AccessDeniedException {
287         allowUpdate();
288         Calendar value = new GregorianCalendar(TimeZone.getDefault());
289         setProperty(this.getInternalPropertyName(LAST_MODIFIED), value);
290     }
291 
292     /**
293      * Get last modified date of the node to which this meta data belongs or null in case such a date can't be determined.
294      * @return Calendar or null when last modification date can't be found.
295      */
296     public Calendar getModificationDate() {
297         return getDateProperty(this.getInternalPropertyName(LAST_MODIFIED));
298     }
299 
300     /**
301      * Part of metadata, last known author of this node.
302      * @return String value of the requested metadata
303      */
304     public String getAuthorId() {
305         return getStringProperty(this.getInternalPropertyName(AUTHOR_ID));
306     }
307 
308     /**
309      * Part of metadata, current logged-in author who did some action on this page.
310      * @param value
311      */
312     public void setAuthorId(String value) throws AccessDeniedException {
313         allowUpdate();
314         setProperty(this.getInternalPropertyName(AUTHOR_ID), value);
315     }
316 
317     /**
318      * Part of metadata, last known activator of this node.
319      * @return String value of the requested metadata
320      */
321     public String getActivatorId() {
322         return getStringProperty(this.getInternalPropertyName(ACTIVATOR_ID));
323     }
324 
325     /**
326      * Part of metadata, current logged-in author who last activated this page.
327      * @param value
328      */
329     public void setActivatorId(String value) throws AccessDeniedException {
330         allowUpdate();
331         setProperty(this.getInternalPropertyName(ACTIVATOR_ID), value);
332     }
333 
334     /**
335      * Part of metadata, template which will be used to render content of this node.
336      * @return String value of the requested metadata
337      */
338     public String getTemplate() {
339         return getStringProperty(this.getInternalPropertyName(TEMPLATE));
340     }
341 
342     /**
343      * Part of metadata, template which will be used to render content of this node.
344      * @param value
345      */
346     public void setTemplate(String value) throws AccessDeniedException {
347         allowUpdate();
348         setProperty(this.getInternalPropertyName(TEMPLATE), value);
349     }
350 
351     /**
352      * Part of metadata, template type : JSP - Servlet - _xxx_.
353      * @param value
354      * @deprecated since 4.0 - not used - template type is determined by template definition
355      */
356     public void setTemplateType(String value) throws AccessDeniedException {
357         allowUpdate();
358         setProperty(this.getInternalPropertyName(TEMPLATE_TYPE), value);
359     }
360 
361     public void setProperty(String name, String value) throws AccessDeniedException {
362         allowUpdate();
363         name = this.getInternalPropertyName(name);
364         try {
365             this.node.getProperty(name).setValue(value);
366         }
367         catch (PathNotFoundException e) {
368             try {
369                 this.node.setProperty(name, value);
370             }
371             catch (RepositoryException re) {
372                 log.error(re.getMessage(), re);
373             }
374         }
375         catch (RepositoryException re) {
376             throw new AccessDeniedException(re.getMessage(), re);
377         }
378         catch (NullPointerException e) {
379             log.debug("MetaData has not been created or this node does not support MetaData. Cannot set property {}", name);
380         }
381     }
382 
383     public void setProperty(String name, long value) throws AccessDeniedException {
384         allowUpdate();
385         name = this.getInternalPropertyName(name);
386         try {
387             this.node.getProperty(name).setValue(value);
388         }
389         catch (PathNotFoundException e) {
390             try {
391                 this.node.setProperty(name, value);
392             }
393             catch (RepositoryException re) {
394                 log.error(re.getMessage(), re);
395             }
396         }
397         catch (RepositoryException re) {
398             log.error(re.getMessage(), re);
399             throw new AccessDeniedException(re.getMessage());
400         }
401         catch (NullPointerException e) {
402             if (log.isDebugEnabled()) {
403                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
404                 log.debug("cannot set property - " + name); //$NON-NLS-1$
405             }
406         }
407     }
408 
409     public void setProperty(String name, double value) throws AccessDeniedException {
410         allowUpdate();
411         name = this.getInternalPropertyName(name);
412         try {
413             this.node.getProperty(name).setValue(value);
414         }
415         catch (PathNotFoundException e) {
416             try {
417                 this.node.setProperty(name, value);
418             }
419             catch (RepositoryException re) {
420                 log.error(re.getMessage(), re);
421             }
422         }
423         catch (RepositoryException re) {
424             log.error(re.getMessage(), re);
425             throw new AccessDeniedException(re.getMessage());
426         }
427         catch (NullPointerException e) {
428             if (log.isDebugEnabled()) {
429                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
430                 log.debug("cannot set property - " + name); //$NON-NLS-1$
431             }
432         }
433     }
434 
435     public void setProperty(String name, boolean value) throws AccessDeniedException {
436         allowUpdate();
437         name = this.getInternalPropertyName(name);
438         try {
439             this.node.getProperty(name).setValue(value);
440         }
441         catch (PathNotFoundException e) {
442             try {
443                 this.node.setProperty(name, value);
444             }
445             catch (RepositoryException re) {
446                 log.error(re.getMessage(), re);
447             }
448         }
449         catch (RepositoryException re) {
450             log.error(re.getMessage(), re);
451             throw new AccessDeniedException(re.getMessage());
452         }
453         catch (NullPointerException e) {
454             if (log.isDebugEnabled()) {
455                 log.debug("MetaData has not been created or this node does not support MetaData"); //$NON-NLS-1$
456                 log.debug("cannot set property - " + name); //$NON-NLS-1$
457             }
458         }
459     }
460 
461     public void setProperty(String name, Calendar value) throws AccessDeniedException {
462         allowUpdate();
463         name = this.getInternalPropertyName(name);
464         try {
465             this.node.getProperty(name).setValue(value);
466         }
467         catch (PathNotFoundException e) {
468             try {
469                 this.node.setProperty(name, value);
470             }
471             catch (RepositoryException re) {
472                 log.error(re.getMessage(), re);
473             }
474         }
475         catch (RepositoryException re) {
476             log.error(re.getMessage(), re);
477             throw new AccessDeniedException(re.getMessage());
478         }
479         catch (NullPointerException e) {
480             log.debug("MetaData has not been created or this node does not support MetaData. Cannot set property {}", name);
481         }
482     }
483 
484     /**
485      * Gets date property or null if such property doesn't exist. Do not use this method for checking existence of the property.
486      */
487     public Calendar getDateProperty(String name) {
488         name = this.getInternalPropertyName(name);
489         try {
490             final Property property = this.node.getProperty(name);
491             return property.getDate();
492         }
493         catch (PathNotFoundException re) {
494             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$ //$NON-NLS-2$
495         }
496         catch (RepositoryException re) {
497             log.error(re.getMessage(), re);
498         }
499         catch (NullPointerException e) {
500             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
501         }
502         return null;
503     }
504 
505     public boolean getBooleanProperty(String name) {
506         name = this.getInternalPropertyName(name);
507         try {
508             final Property property = this.node.getProperty(name);
509             return property.getBoolean();
510         }
511         catch (PathNotFoundException re) {
512             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$ //$NON-NLS-2$
513         }
514         catch (RepositoryException re) {
515             log.error(re.getMessage(), re);
516         }
517         catch (NullPointerException e) {
518             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
519         }
520         return false;
521     }
522 
523     public double getDoubleProperty(String name) {
524         name = this.getInternalPropertyName(name);
525         try {
526             final Property property = this.node.getProperty(name);
527             return property.getDouble();
528         }
529         catch (PathNotFoundException re) {
530             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$ //$NON-NLS-2$
531         }
532         catch (RepositoryException re) {
533             log.error(re.getMessage(), re);
534         }
535         catch (NullPointerException e) {
536             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
537         }
538         return 0d;
539     }
540 
541     public long getLongProperty(String name) {
542         name = this.getInternalPropertyName(name);
543         try {
544             final Property property = this.node.getProperty(name);
545             return property.getLong();
546         }
547         catch (PathNotFoundException re) {
548             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$ //$NON-NLS-2$
549         }
550         catch (RepositoryException re) {
551             log.error(re.getMessage(), re);
552         }
553         catch (NullPointerException e) {
554             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
555         }
556         return 0L;
557     }
558 
559     /**
560      * Returns a String property. If the property does not exist, this will return an empty String.
561      * @param name
562      * @return the property value, never null
563      */
564     public String getStringProperty(String name) {
565         name = this.getInternalPropertyName(name);
566         try {
567             final Property property = this.node.getProperty(name);
568             return property.getString();
569         }
570         catch (PathNotFoundException re) {
571             log.debug("PathNotFoundException for property [{}] in node {}", name, this.node); //$NON-NLS-1$ //$NON-NLS-2$
572         }
573         catch (RepositoryException re) {
574             log.error(re.getMessage(), re);
575         }
576         catch (NullPointerException e) {
577             log.debug("MetaData has not been created or this node does not support MetaData. Cannot get property {}", name);
578         }
579         return StringUtils.EMPTY;
580     }
581 
582 
583     /**
584      * remove specified property.
585      * @param name of the property to be removed
586      * @throws PathNotFoundException if property does not exist
587      * @throws RepositoryException if unable to remove
588      */
589     public void removeProperty(String name) throws PathNotFoundException, RepositoryException {
590         this.node.getProperty(this.getInternalPropertyName(name)).remove();
591     }
592 
593     /**
594      * check if property exists.
595      * @param name
596      * @return true if the specified property exist
597      *
598      * @deprecated since 4.0 - not used
599      */
600     public boolean hasProperty(String name) {
601         try {
602             return this.node.hasProperty(this.getInternalPropertyName(name));
603         }
604         catch (RepositoryException re) {
605             log.error(re.getMessage(), re);
606         }
607         return false;
608     }
609 
610     public String toString() {
611         return new ToStringBuilder(this).append("title", this.getTitle()) //$NON-NLS-1$
612             .append("template", this.getTemplate()) //$NON-NLS-1$
613             .append("authorId", this.getAuthorId()) //$NON-NLS-1$
614             .append("label", this.getLabel()) //$NON-NLS-1$
615             .append("activatorId", this.getActivatorId()) //$NON-NLS-1$
616             .append("isActivated", this.getIsActivated()) //$NON-NLS-1$
617             .append("creationDate", this.getCreationDate()) //$NON-NLS-1$
618             .append("lastActionDate", this.getLastActionDate()) //$NON-NLS-1$
619             .append("modificationDate", this.getModificationDate()) //$NON-NLS-1$
620             .toString();
621     }
622 
623 }