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