View Javadoc
1   /**
2    * This file Copyright (c) 2012-2015 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.jcr.util;
35  
36  import info.magnolia.context.MgnlContext;
37  
38  import java.util.Calendar;
39  
40  import javax.jcr.Node;
41  import javax.jcr.RepositoryException;
42  
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  /**
47   * Magnolia defined NodeTypes together with their properties and some convenience methods.
48   */
49  public class NodeTypes {
50  
51      private static final Logger log = LoggerFactory.getLogger(NodeTypes.class);
52  
53      /**
54       * Namespace for Magnolia extensions.
55       */
56      public static final String MGNL_PREFIX = "mgnl:";
57  
58      /**
59       * Namespace for jcr nodes and properties.
60       */
61      public static final String JCR_PREFIX = "jcr:";
62  
63      /**
64       * Namespace for rep nodes and properties.
65       */
66      public static final String REP_PREFIX = "rep:";
67  
68      /**
69       * Default suffix for userName keeping properties.
70       */
71      private static final String BY = "By";
72  
73      /**
74       * Represents the mixin mgnl:lastModified.
75       */
76      public static class LastModified {
77          public static final String NAME = MGNL_PREFIX + "lastModified";
78          public static final String LAST_MODIFIED = NAME;
79          public static final String LAST_MODIFIED_BY = LAST_MODIFIED + BY;
80  
81          /**
82           * Returns the date when this node was last modified. If the no modification date has been stored on the node this
83           * method return the creation date if set, otherwise null is returned.
84           */
85          public static Calendar getLastModified(Node node) throws RepositoryException {
86              return node.hasProperty(LAST_MODIFIED) ? node.getProperty(LAST_MODIFIED).getDate() : Created.getCreated(node);
87          }
88  
89          /**
90           * Returns the name of the user that last modified the node. If no modification has been stored on the node
91           * this method return the name of the user that created the node if set, otherwise null is returned.
92           */
93          public static String getLastModifiedBy(Node node) throws RepositoryException {
94              return node.hasProperty(LAST_MODIFIED_BY) ? node.getProperty(LAST_MODIFIED_BY).getString() : Created.getCreatedBy(node);
95          }
96  
97          /**
98           * Sets the date of modification to current Calendar and uses {@link info.magnolia.context.MgnlContext} to set the name of the user.
99           * It should not be necessary to call this method explicitly as all Magnolia treated node instances are self updating the property defined by mixin.
100          *
101          * @see info.magnolia.jcr.wrapper.MgnlPropertySettingContentDecorator for more details.
102          */
103         public static void update(Node node) throws RepositoryException {
104             update(node, getCurrentCalendar());
105         }
106 
107         /**
108          * Sets the date of modification.
109          * It should not be necessary to call this method explicitly as all Magnolia treated node instances are self updating the property defined by mixin.
110          *
111          * @see info.magnolia.jcr.wrapper.MgnlPropertySettingContentDecorator for more details.
112          */
113         public static void update(Node node, Calendar lastModified) throws RepositoryException {
114             update(node, getCurrentUserName(), lastModified);
115         }
116 
117         /**
118          * Sets the date of modification and the name of the user modifying a node.
119          * It should not be necessary to call this method explicitly as all Magnolia treated node instances are self updating the property defined by mixin.
120          *
121          * @see info.magnolia.jcr.wrapper.MgnlPropertySettingContentDecorator for more details.
122          */
123         public static void update(Node node, String userName, Calendar lastModified) throws RepositoryException {
124             checkNodeType(node, LastModified.NAME, LAST_MODIFIED, LAST_MODIFIED_BY);
125             node.setProperty(LAST_MODIFIED, lastModified);
126             node.setProperty(LAST_MODIFIED_BY, userName);
127         }
128 
129     }
130 
131     /**
132      * Represents the mixin mgnl:activatable.
133      */
134     public static class Activatable {
135         public static final String NAME = MGNL_PREFIX + "activatable";
136         public static final String LAST_ACTIVATED = MGNL_PREFIX + "lastActivated";
137         public static final String LAST_ACTIVATED_BY = LAST_ACTIVATED + BY;
138         public static final String ACTIVATION_STATUS = MGNL_PREFIX + "activationStatus";
139 
140         public static final int ACTIVATION_STATUS_NOT_ACTIVATED = 0;
141 
142         public static final int ACTIVATION_STATUS_MODIFIED = 1;
143 
144         public static final int ACTIVATION_STATUS_ACTIVATED = 2;
145 
146         /**
147          * Returns the activation status of the node. Returns one of the constants:
148          * <ul>
149          * <li>{@link #ACTIVATION_STATUS_NOT_ACTIVATED} if the node has not been activated</li>
150          * <li>{@link #ACTIVATION_STATUS_MODIFIED} has been activated and subsequently modified</li>
151          * <li>{@link #ACTIVATION_STATUS_ACTIVATED} has been activated and not modified since</li>
152          * </ul>
153          */
154         public static int getActivationStatus(Node node) throws RepositoryException {
155 
156             if (!isActivated(node)) {
157                 // never activated or deactivated
158                 return ACTIVATION_STATUS_NOT_ACTIVATED;
159             }
160 
161             Calendar lastModified = LastModified.getLastModified(node);
162             Calendar lastActivated = getLastActivated(node);
163 
164             if (lastModified != null && lastModified.after(lastActivated)) {
165                 // node has been modified after last activation
166                 return ACTIVATION_STATUS_MODIFIED;
167             }
168 
169             // activated and not modified ever since
170             return ACTIVATION_STATUS_ACTIVATED;
171         }
172 
173         /**
174          * Returns true if the node has been activated.
175          */
176         public static boolean isActivated(Node node) throws RepositoryException {
177             return node.hasProperty(ACTIVATION_STATUS) && node.getProperty(ACTIVATION_STATUS).getBoolean();
178         }
179 
180         /**
181          * Returns the date when the node was last activated or null if no activation date has been stored on the node.
182          */
183         public static Calendar getLastActivated(Node node) throws RepositoryException {
184             return node.hasProperty(LAST_ACTIVATED) ? node.getProperty(LAST_ACTIVATED).getDate() : null;
185         }
186 
187         /**
188          * Returns the name of the user that last activated the node or null if no activating user has been stored on the node.
189          */
190         public static String getLastActivatedBy(Node node) throws RepositoryException {
191             return node.hasProperty(LAST_ACTIVATED_BY) ? node.getProperty(LAST_ACTIVATED_BY).getString() : null;
192         }
193 
194         /**
195          * Sets the name of the user that performed the most recent activation as well as to current time.
196          */
197         public static void update(Node node, String userName, boolean isActivated) throws RepositoryException {
198             checkNodeType(node, Activatable.NAME, LAST_ACTIVATED, LAST_ACTIVATED_BY, ACTIVATION_STATUS);
199             node.setProperty(LAST_ACTIVATED, getCurrentCalendar());
200             node.setProperty(LAST_ACTIVATED_BY, userName);
201             node.setProperty(ACTIVATION_STATUS, isActivated);
202         }
203 
204     }
205 
206     /**
207      * Represents the mixin mgnl:created.
208      */
209     public static class Created {
210         public static final String NAME = MGNL_PREFIX + "created";
211         public static final String CREATED = NAME;
212         public static final String CREATED_BY = CREATED + BY;
213 
214         /**
215          * Returns the creation date of a node or null if creation date isn't set.
216          */
217         public static Calendar getCreated(Node node) throws RepositoryException {
218             return node.hasProperty(CREATED) ? node.getProperty(CREATED).getDate() : null;
219         }
220 
221         /**
222          * Returns the name of the user that created a node.
223          */
224         public static String getCreatedBy(Node node) throws RepositoryException {
225             return node.hasProperty(CREATED_BY) ? node.getProperty(CREATED_BY).getString() : null;
226         }
227 
228         /**
229          * Sets the current date as the node's creation date and uses {@link info.magnolia.context.MgnlContext} to set the name of the creating
230          * user. Used with nodes having the <code>mgnl:created</code> mixin.
231          */
232         public static void set(Node node) throws RepositoryException {
233             set(node, getCurrentUserName(), getCurrentCalendar());
234         }
235 
236         /**
237          * Sets the supplied date as the node's creation date and sets the name of the creating user. Also sets the date of
238          * modification and the user last having modified the node to the same values. Used with nodes having the
239          * <code>mgnl:created</code> mixin.
240          */
241         public static void set(Node node, String userName, Calendar created) throws RepositoryException {
242             checkNodeType(node, NAME, CREATED, CREATED_BY);
243             node.setProperty(CREATED, created);
244             node.setProperty(CREATED_BY, userName);
245 
246             LastModified.update(node, userName, created);
247         }
248     }
249 
250     /**
251      * Represents the mixin mgnl:renderable.
252      */
253     public static class Renderable {
254         public static final String NAME = MGNL_PREFIX + "renderable";
255         public static final String TEMPLATE = MGNL_PREFIX + "template";
256 
257         /**
258          * Returns the template assigned to the node or null of none has been assigned. Used with nodes having the
259          * <code>mgnl:renderable</code> mixin.
260          */
261         public static String getTemplate(Node node) throws RepositoryException {
262             return node.hasProperty(TEMPLATE) ? node.getProperty(TEMPLATE).getString() : null;
263         }
264 
265         /**
266          * Sets the template assigned to the node. Used with nodes having the <code>mgnl:renderable</code> mixin.
267          */
268         public static void set(Node node, String template) throws RepositoryException {
269             checkNodeType(node, NAME, TEMPLATE);
270             node.setProperty(TEMPLATE, template);
271         }
272     }
273 
274     /**
275      * Represents the mixin mgnl:deleted.
276      */
277     public static class Deleted {
278         public static final String NAME = MGNL_PREFIX + "deleted";
279         public static final String DELETED = NAME;
280         public static final String DELETED_BY = DELETED + BY;
281         public static final String COMMENT = MGNL_PREFIX + "comment";
282 
283         /**
284          * Returns the date when the node was deleted or null if no deletion date has been stored on the node.
285          */
286         public static Calendar getDeleted(Node node) throws RepositoryException {
287             return node.hasProperty(DELETED) ? node.getProperty(DELETED).getDate() : null;
288         }
289 
290         /**
291          * Returns the name of the user that deleted the node or null if no deleting user has been stored on the node.
292          */
293         public static String getDeletedBy(Node node) throws RepositoryException {
294             return node.hasProperty(DELETED_BY) ? node.getProperty(DELETED_BY).getString() : null;
295         }
296 
297         /**
298          * Returns the comment set when then node was last deleted or null if no comment has been set.
299          */
300         public static String getComment(Node node) throws RepositoryException {
301             return node.hasProperty(COMMENT) ? node.getProperty(COMMENT).getString() : null;
302         }
303 
304         public static void set(Node node, String comment) throws RepositoryException {
305             checkNodeType(node, NAME, DELETED, DELETED_BY, COMMENT);
306             node.setProperty(DELETED, getCurrentCalendar());
307             node.setProperty(DELETED_BY, getCurrentUserName());
308             node.setProperty(COMMENT, comment);
309         }
310     }
311 
312     /**
313      * Represents the mixin mgnl:versionable.
314      */
315     public static class Versionable {
316         public static final String NAME = MGNL_PREFIX + "versionable";
317         public static final String COMMENT = Deleted.COMMENT;
318 
319         /**
320          * Returns the comment set when then node was last versioned or null if no comment has been set.
321          */
322         public static String getComment(Node node) throws RepositoryException {
323             return node.hasProperty(COMMENT) ? node.getProperty(COMMENT).getString() : null;
324         }
325 
326         /**
327          * Set the versioning comment on the node.
328          */
329         public static void set(Node node, String comment) throws RepositoryException {
330             checkNodeType(node, NAME, COMMENT);
331             node.setProperty(COMMENT, comment);
332         }
333     }
334 
335     /**
336      * Represents the nodeType mgnl:folder.
337      */
338     public static class Folder {
339         public static final String NAME = MGNL_PREFIX + "folder";
340     }
341 
342     /**
343      * Represents the nodeType mgnl:resource.
344      */
345     public static class Resource {
346         public static final String NAME = MGNL_PREFIX + "resource";
347     }
348 
349     /**
350      * Represents the nodeType mgnl:content.
351      */
352     public static class Content {
353         public static final String NAME = MGNL_PREFIX + "content";
354     }
355 
356     /**
357      * Represents the nodeType mgnl:contentNode.
358      */
359     public static class ContentNode {
360         public static final String NAME = MGNL_PREFIX + "contentNode";
361     }
362 
363     /**
364      * Represents the nodeType mgnl:nodeData.
365      */
366     public static class NodeData {
367         public static final String NAME = MGNL_PREFIX + "nodeData";
368     }
369 
370     /**
371      * Represents the nodeType mgnl:page.
372      */
373     public static class Page {
374         public static final String NAME = MGNL_PREFIX + "page";
375     }
376 
377     /**
378      * Represents the nodeType mgnl:area.
379      */
380     public static class Area {
381         public static final String NAME = MGNL_PREFIX + "area";
382     }
383 
384     /**
385      * Represents the nodeType mgnl:component.
386      */
387     public static class Component {
388         public static final String NAME = MGNL_PREFIX + "component";
389     }
390 
391     /**
392      * Represents the nodeType mgnl:user.
393      */
394     public static class User {
395         public static final String NAME = MGNL_PREFIX + "user";
396     }
397 
398     /**
399      * Represents the nodeType mgnl:role.
400      */
401     public static class Role {
402         public static final String NAME = MGNL_PREFIX + "role";
403     }
404 
405     /**
406      * Represents the nodeType mgnl:group.
407      */
408     public static class Group {
409         public static final String NAME = MGNL_PREFIX + "group";
410     }
411 
412     /**
413      * Represents the nodeType mgnl:reserve.
414      */
415     public static class System {
416         public static final String NAME = MGNL_PREFIX + "reserve";
417     }
418 
419     /**
420      * Represents the nodeType mgnl:metaData.
421      * Is basically obsolete since MetaData as mixin but could still be used in customers code,
422      * hence it has to stay for quite a while.
423      */
424     public static class MetaData {
425         public static final String NAME = MGNL_PREFIX + "metaData";
426     }
427 
428     protected static String getCurrentUserName() {
429         return MgnlContext.getUser().getName();
430     }
431 
432     protected static Calendar getCurrentCalendar() {
433         return Calendar.getInstance();
434     }
435 
436     public static void checkNodeType(Node node, String nodeType, String... propertyNames) throws RepositoryException {
437         if (!node.isNodeType(nodeType)) {
438             log.warn("Trying to set property/ies '{}' although the node '{}' with PrimaryType '{}' is not of type '{}'!", propertyNames, node.getPath(), node.getPrimaryNodeType().getName(), nodeType);
439         }
440     }
441 }