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