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