View Javadoc

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