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.util;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.core.HierarchyManager;
38  import info.magnolia.cms.core.NodeData;
39  import info.magnolia.cms.i18n.Messages;
40  import info.magnolia.cms.i18n.MessagesManager;
41  import info.magnolia.cms.i18n.MessagesUtil;
42  import info.magnolia.cms.security.AccessDeniedException;
43  import info.magnolia.context.MgnlContext;
44  import info.magnolia.jcr.util.PropertyUtil;
45  import info.magnolia.repository.RepositoryConstants;
46  
47  import java.io.InputStream;
48  import java.util.Calendar;
49  import java.util.Date;
50  import java.util.List;
51  
52  import javax.jcr.PropertyType;
53  import javax.jcr.RepositoryException;
54  import javax.jcr.Value;
55  import javax.jcr.ValueFactory;
56  
57  import org.apache.commons.lang.StringUtils;
58  import org.apache.commons.lang.time.FastDateFormat;
59  import org.slf4j.Logger;
60  import org.slf4j.LoggerFactory;
61  
62  /**
63   * Util to work with {@link NodeData}.
64   * @author Sameer Charles
65   * @version $Revision$ ($Author$)
66   */
67  public class NodeDataUtil {
68      private static final Logger log = LoggerFactory.getLogger(NodeDataUtil.class);
69  
70      /**
71       * Same as getValueString(nd, dateFormat) but using the users short date format.
72       */
73      public static String getValueString(NodeData nodeData) {
74          String dateFormat = null;
75          if(nodeData.getType() == PropertyType.DATE){
76              try{
77                  dateFormat = FastDateFormat.getDateInstance(
78                          FastDateFormat.SHORT,
79                          MgnlContext.getLocale()).getPattern();
80              }
81              // this happens if the context is not (yet) set
82              catch(IllegalStateException e){
83                  dateFormat = DateUtil.YYYY_MM_DD;
84              }
85          }
86          return getValueString(nodeData, dateFormat);
87      }
88  
89      /**
90       * Returns a String representation of the value. In case of a binary the path including filename and extension is returned
91       * @param nodeData
92       * @param dateFormat date format to use in the case it is a date
93       * @return
94       */
95      public static String getValueString(NodeData nodeData, String dateFormat) {
96          // we can't use FileProperties since this class is in the GUI package
97          if(nodeData.getType()==PropertyType.BINARY){
98              String filename = nodeData.getAttribute("fileName");
99              String ext = nodeData.getAttribute("extension");
100             String fullName = filename;
101             String fullExt = StringUtils.EMPTY;
102             if (StringUtils.isNotEmpty(ext)) {
103                 fullExt = "." + ext;
104                 fullName += fullExt;
105             }
106             return nodeData.getHandle() + "/" + fullName;
107         }
108         else if (nodeData.isMultiValue() == NodeData.MULTIVALUE_TRUE){
109             return StringUtils.join(getValuesStringList(nodeData.getValues()), ",");
110         } else {
111             return getValueString(nodeData.getValue(), dateFormat);
112         }
113     }
114 
115     /**
116      * Same as value.getString(), but using custom date format.
117      */
118     public static String getValueString(Value value, String dateFormat) {
119         try{
120             switch (value.getType()) {
121             case (PropertyType.STRING):
122                 return value.getString();
123             case (PropertyType.DOUBLE):
124                 return Double.toString(value.getDouble());
125             case (PropertyType.LONG):
126                 return Long.toString(value.getLong());
127             case (PropertyType.BOOLEAN):
128                 return Boolean.toString(value.getBoolean());
129             case (PropertyType.DATE):
130                 Date valueDate = value.getDate().getTime();
131             return DateUtil.format(valueDate, dateFormat);
132             case (PropertyType.BINARY):
133                 // ???
134             default:
135                 return StringUtils.EMPTY;
136             }
137         }
138         catch (Exception e) {
139             log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
140         }
141         return StringUtils.EMPTY;
142     }
143 
144     /**
145      * Inherit a value. Uses the string value. The "inherit" means that the method will look for the value in the content itself and if not found
146      * it will go up in the tree and try to locate value in one of the parents of the content until reaching the root. The first value found while
147      * traversing the tree way up is the one that will be returned.
148      * @param node Node expected to define or inherit the searched node value.
149      * @param name Name of the nodeData.
150      */
151     public static String inheritString(Content node, String name) throws RepositoryException{
152         String value = "";
153 
154         if (node.hasNodeData(name)) {
155             value = NodeDataUtil.getString(node, name);
156         }
157         if(StringUtils.isEmpty(value) && node.getLevel() > 0){
158             value = inheritString(node.getParent(), name);
159         }
160         return value;
161     }
162 
163     /**
164      * Inherit a value. You can provide a default value if not found
165      */
166     public static String inheritString(Content node, String name, String dflt) throws RepositoryException{
167         String value = inheritString(node, name);
168         if(StringUtils.isEmpty(value)){
169             return dflt;
170         }
171         return value;
172     }
173 
174     /**
175      * Inherit a value. Uses the string value
176      */
177     public static Object inherit(Content node, String name) throws RepositoryException{
178         Object value = null;
179 
180         if (node.hasNodeData(name)) {
181             value = NodeDataUtil.getValueObject(node.getNodeData(name));
182         }
183         if(value == null && node.getLevel() > 0){
184             value = inherit(node.getParent(), name);
185         }
186         return value;
187     }
188 
189     /**
190      * Inherit a value. You can provide a default value if not found
191      */
192     public static Object inherit(Content node, String name, Object dflt) throws RepositoryException{
193         Object value = inherit(node, name);
194         if(value == null){
195             return dflt;
196         }
197         return value;
198     }
199 
200     /**
201      * Returns the value as an Object.
202      * @return Object
203      */
204     public static Object getValueObject(NodeData nd) {
205         try {
206             switch (nd.getType()) {
207             case (PropertyType.STRING):
208                 return nd.getString();
209             case (PropertyType.DOUBLE):
210                 return Double.valueOf(nd.getDouble());
211             case (PropertyType.LONG):
212                 return Long.valueOf(nd.getLong());
213             case (PropertyType.BOOLEAN):
214                 return Boolean.valueOf(nd.getBoolean());
215             case (PropertyType.DATE):
216                 return nd.getDate().getTime();
217             case (PropertyType.BINARY):
218                 return null;
219             default:
220                 return null;
221             }
222         }
223         catch (Exception e) {
224             log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
225         }
226         return null;
227     }
228 
229     /**
230      * Calls the correct setValue method based on object type. If the value is null an empty string is set.
231      */
232     public static NodeData setValue(NodeData nodeData, Object valueObj) throws AccessDeniedException, RepositoryException{
233         if(valueObj == null){
234             nodeData.setValue(StringUtils.EMPTY);
235         }
236         else{
237             switch (PropertyUtil.getJCRPropertyType(valueObj)) {
238                 case PropertyType.STRING:
239                     nodeData.setValue((String)valueObj);
240                     break;
241                 case PropertyType.BOOLEAN:
242                     nodeData.setValue(((Boolean)valueObj).booleanValue());
243                     break;
244                 case PropertyType.DATE:
245                     nodeData.setValue((Calendar)valueObj);
246                     break;
247                 case PropertyType.LONG:
248                     // can either be a Long or Integer - see #getJCRPropertyType(Object)
249                     long longToSet = (valueObj instanceof Integer) ? ((Integer) valueObj).longValue() : ((Long) valueObj).longValue();
250                     nodeData.setValue(longToSet);
251                     break;
252                 case PropertyType.DOUBLE:
253                     // can either be a Double or Float - see #getJCRPropertyType(Object)
254                     double doubleToSet = (valueObj instanceof Float) ? ((Float) valueObj).doubleValue() : ((Double) valueObj).doubleValue();
255                     nodeData.setValue(doubleToSet);
256                     break;
257                 case PropertyType.BINARY:
258                     nodeData.setValue((InputStream)valueObj);
259                     break;
260                 case PropertyType.REFERENCE:
261                     nodeData.setValue((Content)valueObj);
262                     break;
263                 default:
264                     nodeData.setValue(valueObj.toString());
265             }
266         }
267         return nodeData;
268     }
269 
270 
271     /**
272      * String representation of the jcr property type.
273      */
274     public static String getTypeName(NodeData nd) {
275         return PropertyType.nameFromValue(nd.getType());
276     }
277 
278     /**
279      * Simple method to get strings like configuration informations.
280      */
281     public static String getString(String repository, String path) {
282         return getString(repository, path, null);
283     }
284 
285     /**
286      * Get the string or the empty string if not existing.
287      */
288     public static String getString(Content node, String name) {
289         return getString(node, name, "");
290     }
291 
292     /**
293      * You can define a default value if not found.
294      */
295     public static String getString(String repository, String path, String defaultValue) {
296         try {
297             String name = StringUtils.substringAfterLast(path, "/");
298             String nodeHandle = StringUtils.substringBeforeLast(path, "/");
299             Content node = MgnlContext.getHierarchyManager(repository).getContent(nodeHandle);
300             return getString(node, name);
301         }
302         catch (Exception e) {
303             return defaultValue;
304         }
305     }
306 
307     /**
308      * You can define a default value if not found.
309      */
310     public static String getString(Content node, String name, String defaultValue) {
311         try {
312             if (node.hasNodeData(name)) {
313                 return getValueString(node.getNodeData(name));
314             }
315 
316             return defaultValue;
317         }
318         catch (Exception e) {
319             return defaultValue;
320         }
321     }
322 
323     public static long getLong(Content node, String name, long defaultValue) {
324         try {
325             if(node.hasNodeData(name)){
326                 return node.getNodeData(name).getLong();
327             }
328         }
329         // should not happen
330         catch (RepositoryException e) {
331             log.error("can't read value will return default value", e);
332         }
333         return defaultValue;
334     }
335 
336     public static Calendar getDate(Content node, String name, Calendar defaultValue) {
337         try {
338             if(node.hasNodeData(name)){
339                 return node.getNodeData(name).getDate();
340             }
341         }
342         // should not happen
343         catch (RepositoryException e) {
344             log.error("can't read value will return default value", e);
345         }
346         return defaultValue;
347     }
348 
349     public static boolean getBoolean(Content node, String name, boolean defaultValue) {
350         try {
351             if(node.hasNodeData(name)){
352                 return node.getNodeData(name).getBoolean();
353             }
354         }
355         // should not happen
356         catch (RepositoryException e) {
357             log.error("can't read value will return default value", e);
358         }
359         return defaultValue;
360     }
361 
362     /**
363      * If the NodeData does not exist yet, just create it.
364      * @param node
365      * @param name
366      * @return the found or created NodeData
367      * @throws AccessDeniedException
368      * @throws RepositoryException
369      */
370     public static NodeData getOrCreate(Content node, String name) throws AccessDeniedException, RepositoryException {
371         return getOrCreate(node, name, PropertyType.STRING);
372     }
373 
374     /**
375      * If the NodeData does not exist yet, just create it.
376      * @param node
377      * @param name
378      * @return the found or created NodeData
379      * @throws AccessDeniedException
380      * @throws RepositoryException
381      */
382     public static NodeData getOrCreate(Content node, String name, int type) throws AccessDeniedException,
383     RepositoryException {
384         if (node.hasNodeData(name)) {
385             return node.getNodeData(name);
386         }
387 
388         return node.createNodeData(name, type);
389     }
390 
391     public static NodeData getOrCreate(Content node, String name, Object obj) throws AccessDeniedException,
392     RepositoryException {
393 
394         return getOrCreate(node, name, PropertyUtil.getJCRPropertyType(obj));
395     }
396 
397 
398     public static NodeData getOrCreateAndSet(Content node, String name, Object obj) throws AccessDeniedException, RepositoryException {
399         // TODO we should not use the jcr node
400         ValueFactory valueFactory = node.getJCRNode().getSession().getValueFactory();
401         NodeData nd = getOrCreate(node, name, PropertyUtil.getJCRPropertyType(obj));
402         nd.setValue(createValue(obj, valueFactory));
403         return nd;
404     }
405 
406     public static NodeData getOrCreateAndSet(Content node, String name, long value) throws AccessDeniedException, RepositoryException {
407         return getOrCreateAndSet(node, name, Long.valueOf(value));
408     }
409 
410     public static NodeData getOrCreateAndSet(Content node, String name, Value[] value) throws AccessDeniedException, RepositoryException {
411         if (node.hasNodeData(name)) {
412             node.setNodeData(name, value);
413             return node.getNodeData(name);
414         }
415 
416         return node.createNodeData(name, value);
417 
418     }
419 
420     public static NodeData getOrCreateAndSet(Content node, String name, int value) throws AccessDeniedException, RepositoryException {
421         return getOrCreateAndSet(node, name, Long.valueOf(value));
422     }
423 
424     public static NodeData getOrCreateAndSet(Content node, String name, boolean value) throws AccessDeniedException, RepositoryException {
425         return getOrCreateAndSet(node, name, Boolean.valueOf(value));
426     }
427 
428     /**
429      * Uses the i18n mechanism to translate the message if the resulting string is a key.
430      */
431     public static String getI18NString(Content node, String str) {
432         Messages msgs = MessagesManager.getMessages();
433         String key = getString(node, str);
434         String i18nBasename = null;
435         try {
436             i18nBasename = NodeDataUtil.inheritString(node, "i18nBasename");
437         }
438         catch (RepositoryException e) {
439             log.error("can't read i18nBasename value, will default back", e);
440         }
441 
442         if (StringUtils.isNotEmpty(i18nBasename)) {
443             msgs = MessagesUtil.chainWithDefault(i18nBasename);
444         }
445 
446         return msgs.getWithDefault(key, key);
447     }
448 
449     /**
450      * Uses the i18n mechanism to translate the message if the resulting string is a key.
451      */
452     public static String getI18NString(Content node, String str, String basename) {
453         String key = getString(node, str);
454         return MessagesManager.getMessages(basename).getWithDefault(key, key);
455     }
456 
457     /**
458      * Uses the default value factory.
459      */
460     public static Value createValue(String valueStr, int type) throws RepositoryException {
461         HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);
462         ValueFactory valueFactory = hm.getWorkspace().getSession().getValueFactory();
463         return createValue(valueStr, type, valueFactory);
464     }
465 
466     /**
467      * @deprecated since 4.5 - use {@link PropertyUtil#createValue(Object, ValueFactory)} instead
468      */
469     public static Value createValue(Object obj, ValueFactory valueFactory) throws RepositoryException {
470         return PropertyUtil.createValue(obj, valueFactory);
471     }
472 
473     /**
474      * Transforms a string to a jcr value object.
475      *
476      * @deprecated since 4.5 - directly use {@link PropertyUtil#createValue(String, int, ValueFactory)} instead.
477      */
478     public static Value createValue(String valueStr, int type, ValueFactory valueFactory) {
479         return PropertyUtil.createValue(valueStr, type, valueFactory);
480     }
481 
482     /**
483      * @deprecated since 4.5 - use {@link PropertyUtil#getJCRPropertyType(Object)} instead
484      */
485     public static int getJCRPropertyType(Object obj) {
486         return PropertyUtil.getJCRPropertyType(obj);
487     }
488 
489     /**
490      * @deprecated since 4.5  - use {@link PropertyUtil#getValuesStringList(Value[])} instead
491      */
492     public static List<String> getValuesStringList(Value[] values) {
493         return PropertyUtil.getValuesStringList(values);
494     }
495 
496     /**
497      * @deprecated since 4.5 - use {@link PropertyUtil#getDateFormat()} instead
498      */
499     public static String getDateFormat() {
500         return PropertyUtil.getDateFormat();
501     }
502 }