View Javadoc

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