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.util;
35  
36  import info.magnolia.cms.beans.config.ContentRepository;
37  import info.magnolia.cms.core.Content;
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.cms.core.HierarchyManager;
45  
46  import java.io.InputStream;
47  import java.util.ArrayList;
48  import java.util.Calendar;
49  import java.util.Date;
50  import java.util.GregorianCalendar;
51  import java.util.List;
52  import java.util.TimeZone;
53  
54  import javax.jcr.PathNotFoundException;
55  import javax.jcr.PropertyType;
56  import javax.jcr.RepositoryException;
57  import javax.jcr.Value;
58  import javax.jcr.ValueFactory;
59  
60  import org.apache.commons.lang.BooleanUtils;
61  import org.apache.commons.lang.StringUtils;
62  import org.apache.commons.lang.time.FastDateFormat;
63  import org.slf4j.Logger;
64  import org.slf4j.LoggerFactory;
65  
66  /**
67   * @author Sameer Charles
68   * @version $Revision: 32667 $ ($Author: gjoseph $)
69   */
70  public class NodeDataUtil {
71      private static final Logger log = LoggerFactory.getLogger(NodeDataUtil.class);
72  
73      /**
74       * Same as getValueString(nd, dateFormat) but using the users short date format
75       */
76      public static String getValueString(NodeData nodeData) {
77          String dateFormat = null;
78          if(nodeData.getType() == PropertyType.DATE){
79              try{
80                  dateFormat = FastDateFormat.getDateInstance(
81                  FastDateFormat.SHORT,
82                  MgnlContext.getLocale()).getPattern();
83              }
84              // this happens if the context is not (yet) set
85              catch(IllegalStateException e){
86                  dateFormat = DateUtil.YYYY_MM_DD;
87              }
88          }
89          return getValueString(nodeData, dateFormat);
90      }
91  
92      /**
93       * Returns a String representation of the value. In case of a binary the path including filename and extension is returned
94       * @param nodeData
95       * @param dateFormat date format to use in the case it is a date
96       * @return
97       */
98      public static String getValueString(NodeData nodeData, String dateFormat) {
99          // we can't use FileProperties since this class is in the GUI package
100         if(nodeData.getType()==PropertyType.BINARY){
101             String filename = nodeData.getAttribute("fileName");
102             String ext = nodeData.getAttribute("extension");
103             String fullName = filename;
104             String fullExt = StringUtils.EMPTY;
105             if (StringUtils.isNotEmpty(ext)) {
106                 fullExt = "." + ext;
107                 fullName += fullExt;
108             }
109             return nodeData.getHandle() + "/" + fullName;
110         }
111         else if (nodeData.isMultiValue() == NodeData.MULTIVALUE_TRUE){
112             return StringUtils.join(getValuesStringList(nodeData.getValues()), ",");
113         } else {
114             return getValueString(nodeData.getValue(), dateFormat);
115         }
116     }
117 
118     /**
119      * Same as value.getString(), but using custom date format
120      * @param value
121      * @param dateFormat
122      * @return
123      */
124     public static String getValueString(Value value, String dateFormat) {
125         try{
126             switch (value.getType()) {
127                 case (PropertyType.STRING):
128                     return value.getString();
129                 case (PropertyType.DOUBLE):
130                     return Double.toString(value.getDouble());
131                 case (PropertyType.LONG):
132                     return Long.toString(value.getLong());
133                 case (PropertyType.BOOLEAN):
134                     return Boolean.toString(value.getBoolean());
135                 case (PropertyType.DATE):
136                     Date valueDate = value.getDate().getTime();
137                     return DateUtil.format(valueDate, dateFormat);
138                 case (PropertyType.BINARY):
139                     // ???
140                 default:
141                     return StringUtils.EMPTY;
142             }
143         }
144         catch (Exception e) {
145             log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
146         }
147         return StringUtils.EMPTY;
148     }
149 
150     /**
151      * 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
152      * 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
153      * traversing the tree way up is the one that will be returned.
154      * @param node Node expected to define or inherit the searched node value.
155      * @param name Name of the nodeData.
156      */
157     public static String inheritString(Content node, String name) throws RepositoryException{
158         String value = "";
159 
160         if (node.hasNodeData(name)) {
161             value = NodeDataUtil.getString(node, name);
162         }
163         if(StringUtils.isEmpty(value) && node.getLevel() > 0){
164             value = inheritString(node.getParent(), name);
165         }
166         return value;
167     }
168 
169     /**
170      * Inherit a value. You can provide a default value if not found
171      */
172     public static String inheritString(Content node, String name, String dflt) throws RepositoryException{
173         String value = inheritString(node, name);
174         if(StringUtils.isEmpty(value)){
175             return dflt;
176         }
177         return value;
178     }
179 
180     /**
181      * Inherit a value. Uses the string value
182      */
183     public static Object inherit(Content node, String name) throws RepositoryException{
184         Object value = null;
185 
186         if (node.hasNodeData(name)) {
187             value = NodeDataUtil.getValueObject(node.getNodeData(name));
188         }
189         if(value == null && node.getLevel() > 0){
190             value = inherit(node.getParent(), name);
191         }
192         return value;
193     }
194 
195     /**
196      * Inherit a value. You can provide a default value if not found
197      */
198     public static Object inherit(Content node, String name, Object dflt) throws RepositoryException{
199         Object value = inherit(node, name);
200         if(value == null){
201             return dflt;
202         }
203         return value;
204     }
205 
206     /**
207      * Returns the value as an Object.
208      * @return Object
209      */
210     public static Object getValueObject(NodeData nd) {
211         try {
212             switch (nd.getType()) {
213                 case (PropertyType.STRING):
214                     return nd.getString();
215                 case (PropertyType.DOUBLE):
216                     return new Double(nd.getDouble());
217                 case (PropertyType.LONG):
218                     return new Long(nd.getLong());
219                 case (PropertyType.BOOLEAN):
220                     return Boolean.valueOf(nd.getBoolean());
221                 case (PropertyType.DATE):
222                     return nd.getDate().getTime();
223                 case (PropertyType.BINARY):
224                     return null;
225                 default:
226                     return null;
227             }
228         }
229         catch (Exception e) {
230             log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
231         }
232         return null;
233     }
234     
235     /**
236      * Calls the correct setValue method based on object type. If the value is null an empty string is set.
237      */
238     public static NodeData setValue(NodeData nodeData, Object valueObj) throws AccessDeniedException, RepositoryException{
239         if(valueObj == null){
240             nodeData.setValue(StringUtils.EMPTY);
241         }
242         else{
243             switch (getJCRPropertyType(valueObj)) {
244                 case PropertyType.STRING:
245                     nodeData.setValue((String)valueObj);
246                     break;
247                 case PropertyType.BOOLEAN:
248                     nodeData.setValue(((Boolean)valueObj).booleanValue());
249                     break;
250                 case PropertyType.DATE:
251                     nodeData.setValue((Calendar)valueObj);
252                     break;
253                 case PropertyType.LONG:
254                     nodeData.setValue(((Long)valueObj).longValue());
255                     break;
256                 case PropertyType.DOUBLE:
257                     nodeData.setValue(((Double)valueObj).doubleValue());
258                     break;
259                 case PropertyType.BINARY:
260                     nodeData.setValue((InputStream)valueObj);
261                     break;
262                 case PropertyType.REFERENCE:
263                     nodeData.setValue((Content)valueObj);
264                     break;
265                 default:
266                     nodeData.setValue(valueObj.toString());
267             }
268         }
269         return nodeData;
270     }
271     
272 
273     /**
274      * String representation of the jcr property type
275      */
276     public static String getTypeName(NodeData nd) {
277         return PropertyType.nameFromValue(nd.getType());
278     }
279 
280     /**
281      * Simple method to get strings like configuration informations
282      * @param repository
283      * @param path
284      * @return
285      */
286     public static String getString(String repository, String path) {
287         return getString(repository, path, null);
288     }
289 
290     /**
291      * Get the string or the empty string if not existing
292      * @param node
293      * @param name
294      * @return a string
295      */
296     public static String getString(Content node, String name) {
297         return getString(node, name, "");
298     }
299 
300     /**
301      * You can define a default value if not found
302      * @param repository
303      * @param path
304      * @param defaultValue
305      * @return the string
306      */
307     public static String getString(String repository, String path, String defaultValue) {
308         try {
309             String name = StringUtils.substringAfterLast(path, "/");
310             String nodeHandle = StringUtils.substringBeforeLast(path, "/");
311             Content node = MgnlContext.getHierarchyManager(repository).getContent(nodeHandle);
312             return getString(node, name);
313         }
314         catch (Exception e) {
315             return defaultValue;
316         }
317     }
318 
319     /**
320      * You can define a default value if not found
321      * @param node
322      * @param name
323      * @param defaultValue
324      * @return the string
325      */
326     public static String getString(Content node, String name, String defaultValue) {
327         try {
328             if (node.hasNodeData(name)) {
329                 return getValueString(node.getNodeData(name));
330             }
331 
332             return defaultValue;
333         }
334         catch (Exception e) {
335             return defaultValue;
336         }
337     }
338 
339     public static long getLong(Content node, String name, long defaultValue) {
340         try {
341             if(node.hasNodeData(name)){
342                 return node.getNodeData(name).getLong();
343             }
344         }
345         // should not happen
346         catch (RepositoryException e) {
347             log.error("can't read value will return default value", e);
348         }
349         return defaultValue;
350     }
351 
352     public static Calendar getDate(Content node, String name, Calendar defaultValue) {
353         try {
354             if(node.hasNodeData(name)){
355                 return node.getNodeData(name).getDate();
356             }
357         }
358         // should not happen
359         catch (RepositoryException e) {
360             log.error("can't read value will return default value", e);
361         }
362         return defaultValue;
363     }
364 
365     public static boolean getBoolean(Content node, String name, boolean defaultValue) {
366         try {
367             if(node.hasNodeData(name)){
368                 return node.getNodeData(name).getBoolean();
369             }
370         }
371         // should not happen
372         catch (RepositoryException e) {
373             log.error("can't read value will return default value", e);
374         }
375         return defaultValue;
376     }
377 
378     /**
379      * If the NodeData does not exist yet, just create it.
380      * @param node
381      * @param name
382      * @return the found or created NodeData
383      * @throws AccessDeniedException
384      * @throws PathNotFoundException
385      * @throws RepositoryException
386      */
387     public static NodeData getOrCreate(Content node, String name) throws AccessDeniedException, RepositoryException {
388         return getOrCreate(node, name, PropertyType.STRING);
389     }
390 
391     /**
392      * If the NodeData does not exist yet, just create it.
393      * @param node
394      * @param name
395      * @return the found or created NodeData
396      * @throws AccessDeniedException
397      * @throws PathNotFoundException
398      * @throws RepositoryException
399      */
400     public static NodeData getOrCreate(Content node, String name, int type) throws AccessDeniedException,
401         RepositoryException {
402         if (node.hasNodeData(name)) {
403             return node.getNodeData(name);
404         }
405 
406         return node.createNodeData(name, type);
407     }
408 
409     public static NodeData getOrCreate(Content node, String name, Object obj) throws AccessDeniedException,
410         RepositoryException {
411 
412         return getOrCreate(node, name, getJCRPropertyType(obj));
413     }
414 
415 
416     public static NodeData getOrCreateAndSet(Content node, String name, Object obj) throws AccessDeniedException, RepositoryException {
417         // TODO we should not use the jcr node
418         ValueFactory valueFactory = node.getJCRNode().getSession().getValueFactory();
419         NodeData nd = getOrCreate(node, name, getJCRPropertyType(obj));
420         nd.setValue(createValue(obj, valueFactory));
421         return nd;
422     }
423 
424     public static NodeData getOrCreateAndSet(Content node, String name, long value) throws AccessDeniedException, RepositoryException {
425         return getOrCreateAndSet(node, name, new Long(value));
426     }
427 
428     public static NodeData getOrCreateAndSet(Content node, String name, Value[] value) throws AccessDeniedException, RepositoryException {
429         if (node.hasNodeData(name)) {
430             node.setNodeData(name, value);
431             return node.getNodeData(name);
432         }
433 
434         return node.createNodeData(name, value);
435 
436     }
437 
438     public static NodeData getOrCreateAndSet(Content node, String name, int value) throws AccessDeniedException, RepositoryException {
439         return getOrCreateAndSet(node, name, new Long(value));
440     }
441 
442     public static NodeData getOrCreateAndSet(Content node, String name, boolean value) throws AccessDeniedException, RepositoryException {
443         return getOrCreateAndSet(node, name, new Boolean(value));
444     }
445 
446     /**
447      * Uses the i18n mechanism to translate the message if the resulting string is a key.
448      */
449     public static String getI18NString(Content node, String str) {
450         Messages msgs = MessagesManager.getMessages();
451         String key = getString(node, str);
452         String i18nBasename = null;
453         try {
454             i18nBasename = NodeDataUtil.inheritString(node, "i18nBasename");
455         }
456         catch (RepositoryException e) {
457             log.error("can't read i18nBasename value, will default back", e);
458         }
459 
460         if (StringUtils.isNotEmpty(i18nBasename)) {
461             msgs = MessagesUtil.chainWithDefault(i18nBasename);
462         }
463 
464         return msgs.getWithDefault(key, key);
465     }
466 
467     /**
468      * Uses the i18n mechanism to translate the message if the resulting string is a key
469      */
470     public static String getI18NString(Content node, String str, String basename) {
471         String key = getString(node, str);
472         return MessagesManager.getMessages(basename).getWithDefault(key, key);
473     }
474 
475     /**
476      * Uses the default value factory
477      * @param valueStr
478      * @param type
479      * @return
480      * @throws RepositoryException
481      */
482     public static Value createValue(String valueStr, int type) throws RepositoryException {
483         HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(ContentRepository.CONFIG);
484         ValueFactory valueFactory = hm.getWorkspace().getSession().getValueFactory();
485         return createValue(valueStr, type, valueFactory);
486     }
487 
488     public static Value createValue(Object obj, ValueFactory valueFactory) throws RepositoryException {
489         switch (getJCRPropertyType(obj)) {
490             case PropertyType.STRING:
491                 return valueFactory.createValue((String)obj);
492             case PropertyType.BOOLEAN:
493                 return valueFactory.createValue(((Boolean)obj).booleanValue());
494             case PropertyType.DATE:
495                 return valueFactory.createValue((Calendar)obj);
496             case PropertyType.LONG:
497                 return valueFactory.createValue(((Long)obj).longValue());
498             case PropertyType.DOUBLE:
499                 return valueFactory.createValue(((Double)obj).doubleValue());
500             case PropertyType.BINARY:
501                 return valueFactory.createValue((InputStream)obj);
502             case PropertyType.REFERENCE:
503                 return valueFactory.createValue(((Content)obj).getJCRNode());
504             default:
505                 return (obj != null ? valueFactory.createValue(obj.toString()) : valueFactory.createValue(StringUtils.EMPTY));
506         }
507     }
508 
509     /**
510      * Transforms a string to a jcr value object
511      * @param valueStr
512      * @param type
513      * @param valueFactory
514      * @return the value
515      */
516     public static Value createValue(String valueStr, int type, ValueFactory valueFactory) {
517         Value value = null;
518         if (type == PropertyType.STRING) {
519             value = valueFactory.createValue(valueStr);
520         }
521         else if (type == PropertyType.BOOLEAN) {
522             value = valueFactory.createValue(BooleanUtils.toBoolean(valueStr));
523         }
524         else if (type == PropertyType.DOUBLE) {
525             try {
526                 value = valueFactory.createValue(Double.parseDouble(valueStr));
527             }
528             catch (NumberFormatException e) {
529                 value = valueFactory.createValue(0d);
530             }
531         }
532         else if (type == PropertyType.LONG) {
533             try {
534                 value = valueFactory.createValue(Long.parseLong(valueStr));
535             }
536             catch (NumberFormatException e) {
537                 value = valueFactory.createValue(0L);
538             }
539         }
540         else if (type == PropertyType.DATE) {
541             try {
542                 Calendar date = new GregorianCalendar();
543                 try {
544                     String newDateAndTime = valueStr;
545                     String[] dateAndTimeTokens = newDateAndTime.split("T"); //$NON-NLS-1$
546                     String newDate = dateAndTimeTokens[0];
547                     String[] dateTokens = newDate.split("-"); //$NON-NLS-1$
548                     int hour = 0;
549                     int minute = 0;
550                     int second = 0;
551                     int year = Integer.parseInt(dateTokens[0]);
552                     int month = Integer.parseInt(dateTokens[1]) - 1;
553                     int day = Integer.parseInt(dateTokens[2]);
554                     if (dateAndTimeTokens.length > 1) {
555                         String newTime = dateAndTimeTokens[1];
556                         String[] timeTokens = newTime.split(":"); //$NON-NLS-1$
557                         hour = Integer.parseInt(timeTokens[0]);
558                         minute = Integer.parseInt(timeTokens[1]);
559                         second = Integer.parseInt(timeTokens[2]);
560                     }
561                     date.set(year, month, day, hour, minute, second);
562                     // this is used in the searching
563                     date.set(Calendar.MILLISECOND, 0);
564                     date.setTimeZone(TimeZone.getTimeZone("GMT"));
565                 }
566                 // todo time zone??
567                 catch (Exception e) {
568                     // ignore, it sets the current date / time
569                 }
570                 value = valueFactory.createValue(date);
571             }
572             catch (Exception e) {
573                 log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
574             }
575         }
576 
577         return value;
578 
579     }
580 
581     public static int getJCRPropertyType(Object obj) {
582         if(obj instanceof String) {
583             return PropertyType.STRING;
584         }
585         if(obj instanceof Double) {
586             return PropertyType.DOUBLE;
587         }
588         if(obj instanceof Long) {
589             return PropertyType.LONG;
590         }
591         if(obj instanceof Integer) {
592             return PropertyType.LONG;
593         }
594         if(obj instanceof Boolean) {
595             return PropertyType.BOOLEAN;
596         }
597         if(obj instanceof Calendar) {
598             return PropertyType.DATE;
599         }
600         if(obj instanceof InputStream) {
601             return PropertyType.BINARY;
602         }
603         if(obj instanceof Content) {
604             return PropertyType.REFERENCE;
605         }
606         return PropertyType.UNDEFINED;
607     }
608 
609     public static List<String> getValuesStringList(Value[] values) {
610         ArrayList<String> list = new ArrayList<String>();
611         try{
612             Value value;
613             for( int i = 0; i < values.length; i++) {
614                 value = values[i];
615                 switch (value.getType()) {
616                     case (PropertyType.STRING):
617                         list.add(value.getString());
618                         break;
619                     case (PropertyType.DOUBLE):
620                         list.add(Double.toString(value.getDouble()));
621                         break;
622                     case (PropertyType.LONG):
623                         list.add(Long.toString(value.getLong()));
624                         break;
625                     case (PropertyType.BOOLEAN):
626                         list.add(Boolean.toString(value.getBoolean()));
627                         break;
628                     case (PropertyType.DATE):
629                         Date valueDate = value.getDate().getTime();
630                         list.add(DateUtil.format(valueDate, NodeDataUtil.getDateFormat()));
631                         break;
632                     case (PropertyType.BINARY):
633                         // for lack of better solution, fall through to the default - empty string
634                     default:
635                         list.add(StringUtils.EMPTY);
636                 }
637             }
638         }
639         catch (Exception e) {
640             log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
641         }
642         return list;
643     }
644 
645     public static String getDateFormat() {
646         String dateFormat = null;
647         try{
648             dateFormat = FastDateFormat.getDateInstance(
649             FastDateFormat.SHORT,
650             MgnlContext.getLocale()).getPattern();
651         }
652         // this happens if the context is not (yet) set
653         catch(IllegalStateException e){
654             dateFormat = DateUtil.YYYY_MM_DD;
655         }
656         return dateFormat;
657     }
658 }