View Javadoc

1   /**
2    * This file Copyright (c) 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.jcr.util;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.util.DateUtil;
38  import info.magnolia.context.MgnlContext;
39  
40  import java.io.InputStream;
41  import java.math.BigDecimal;
42  import java.util.ArrayList;
43  import java.util.Calendar;
44  import java.util.Date;
45  import java.util.GregorianCalendar;
46  import java.util.List;
47  import java.util.TimeZone;
48  
49  import javax.jcr.Binary;
50  import javax.jcr.Node;
51  import javax.jcr.PathNotFoundException;
52  import javax.jcr.Property;
53  import javax.jcr.PropertyType;
54  import javax.jcr.RepositoryException;
55  import javax.jcr.Value;
56  import javax.jcr.ValueFactory;
57  
58  import org.apache.commons.lang.BooleanUtils;
59  import org.apache.commons.lang.StringUtils;
60  import org.apache.commons.lang.time.FastDateFormat;
61  import org.slf4j.Logger;
62  import org.slf4j.LoggerFactory;
63  
64  /**
65   * Property-related utility methods.
66   *
67   * @version $Id$
68   */
69  public class PropertyUtil {
70  
71      private static final Logger log = LoggerFactory.getLogger(PropertyUtil.class);
72  
73      public static void renameProperty(Property property, String newName) throws RepositoryException {
74          Node node = property.getParent();
75          node.setProperty(newName, property.getValue());
76          property.remove();
77      }
78  
79      /**
80       * Allows setting a Node's property from an object.
81       */
82      public static void setProperty(Node node, String propertyName, Object propertyValue) throws RepositoryException {
83          if (node == null) {
84              throw new IllegalArgumentException("Cannot set a property on a null-node!");
85          }
86          if (propertyName == null) {
87              throw new IllegalArgumentException("Cannot set a property without a provided name");
88          }
89  
90          if (propertyValue == null){
91              node.setProperty(propertyName, (Value) null);
92          } else if (propertyValue instanceof Value) {
93              node.setProperty(propertyName, (Value) propertyValue);
94          } else if (propertyValue instanceof Node) {
95              node.setProperty(propertyName, (Node) propertyValue);
96          } else if (propertyValue instanceof Binary) {
97              node.setProperty(propertyName, (Binary) propertyValue);
98          } else if (propertyValue instanceof Calendar) {
99              node.setProperty(propertyName, (Calendar) propertyValue);
100         } else if (propertyValue instanceof BigDecimal) {
101             node.setProperty(propertyName, (BigDecimal) propertyValue);
102         } else if (propertyValue instanceof String) {
103             node.setProperty(propertyName, (String) propertyValue);
104         } else if (propertyValue instanceof Long) {
105             node.setProperty(propertyName, ((Long) propertyValue).longValue());
106         } else if (propertyValue instanceof Double) {
107             node.setProperty(propertyName, (Double) propertyValue);
108         } else if (propertyValue instanceof Boolean) {
109             node.setProperty(propertyName, (Boolean) propertyValue);
110         } else if (propertyValue instanceof InputStream) {
111             node.setProperty(propertyName, (InputStream) propertyValue);
112         } else {
113             // TODO dlipp: verify if this is desired default-behavior: NodeDataUtil#setValue sets propertyValue.toString() as default!
114             throw new IllegalArgumentException("Cannot set property to a value of type " + propertyValue.getClass());
115         }
116     }
117 
118     /**
119      * Transforms a string to a jcr value object.
120      */
121     public static Value createValue(String valueStr, int type, ValueFactory valueFactory) {
122         Value value = null;
123         if (type == PropertyType.STRING) {
124             value = valueFactory.createValue(valueStr);
125         } else if (type == PropertyType.BOOLEAN) {
126             value = valueFactory.createValue(BooleanUtils.toBoolean(valueStr));
127         } else if (type == PropertyType.DOUBLE) {
128             try {
129                 value = valueFactory.createValue(Double.parseDouble(valueStr));
130             } catch (NumberFormatException e) {
131                 value = valueFactory.createValue(0d);
132             }
133         } else if (type == PropertyType.LONG) {
134             try {
135                 value = valueFactory.createValue(Long.parseLong(valueStr));
136             } catch (NumberFormatException e) {
137                 value = valueFactory.createValue(0L);
138             }
139         } else if (type == PropertyType.DATE) {
140             try {
141                 Calendar date = new GregorianCalendar();
142                 try {
143                     String newDateAndTime = valueStr;
144                     String[] dateAndTimeTokens = newDateAndTime.split("T");
145                     String newDate = dateAndTimeTokens[0];
146                     String[] dateTokens = newDate.split("-");
147                     int hour = 0;
148                     int minute = 0;
149                     int second = 0;
150                     int year = Integer.parseInt(dateTokens[0]);
151                     int month = Integer.parseInt(dateTokens[1]) - 1;
152                     int day = Integer.parseInt(dateTokens[2]);
153                     if (dateAndTimeTokens.length > 1) {
154                         String newTime = dateAndTimeTokens[1];
155                         String[] timeTokens = newTime.split(":");
156                         hour = Integer.parseInt(timeTokens[0]);
157                         minute = Integer.parseInt(timeTokens[1]);
158                         second = Integer.parseInt(timeTokens[2]);
159                     }
160                     date.set(year, month, day, hour, minute, second);
161                     // this is used in the searching
162                     date.set(Calendar.MILLISECOND, 0);
163                     date.setTimeZone(TimeZone.getTimeZone("GMT"));
164                 }
165                 // todo time zone??
166                 catch (Exception e) {
167                     // ignore, it sets the current date / time
168                 }
169                 value = valueFactory.createValue(date);
170             } catch (Exception e) {
171                 log.debug("Exception caught: " + e.getMessage(), e);
172             }
173         }
174 
175         return value;
176 
177     }
178 
179     /**
180      * @return JCR-PropertyType corresponding to provided Object.
181      */
182     public static int getJCRPropertyType(Object obj) {
183         if (obj instanceof String) {
184             return PropertyType.STRING;
185         }
186         if (obj instanceof Double) {
187             return PropertyType.DOUBLE;
188         }
189         if (obj instanceof Float) {
190             return PropertyType.DOUBLE;
191         }
192         if (obj instanceof Long) {
193             return PropertyType.LONG;
194         }
195         if (obj instanceof Integer) {
196             return PropertyType.LONG;
197         }
198         if (obj instanceof Boolean) {
199             return PropertyType.BOOLEAN;
200         }
201         if (obj instanceof Calendar) {
202             return PropertyType.DATE;
203         }
204         if (obj instanceof Binary) {
205             return PropertyType.BINARY;
206         }
207         if (obj instanceof InputStream) {
208             return PropertyType.BINARY;
209         }
210         if (obj instanceof Content) {
211             return PropertyType.REFERENCE;
212         }
213         return PropertyType.UNDEFINED;
214     }
215 
216     /**
217      * Updates existing property or creates a new one if it doesn't exist already.
218      */
219     public static void updateOrCreate(Node node, String string, GregorianCalendar gregorianCalendar) throws RepositoryException {
220         if (node.hasProperty(string)) {
221             node.getProperty(string).setValue(gregorianCalendar);
222         } else {
223             node.setProperty(string, gregorianCalendar);
224         }
225     }
226 
227     public static String getDateFormat() {
228         try {
229             return FastDateFormat.getDateInstance(
230                     FastDateFormat.SHORT,
231                     MgnlContext.getLocale()).getPattern();
232         } catch (IllegalStateException e) {
233             // this happens if the context is not (yet) set
234             return DateUtil.YYYY_MM_DD;
235         }
236     }
237 
238     public static List<String> getValuesStringList(Value[] values) {
239         ArrayList<String> list = new ArrayList<String>();
240         for (Value value : values) {
241             list.add(getValueString(value));
242         }
243         return list;
244     }
245 
246     /**
247      * Returns value of the property converted to string no matter what it's type actually is. In case of dates, value if formatted according to format returned by {@link #getDateFormat()}. Binary and reference values are converted to empty string. In case of error during conversion, null will be returned instead. Works only for single value properties.
248      */
249     public static String getValueString(Property property) {
250         try {
251             return getValueString(property.getValue());
252         } catch (RepositoryException e) {
253             log.debug("RepositoryException caught: " + e.getMessage(), e);
254             return null;
255         }
256     }
257 
258     /**
259      * Returns value converted to string no matter what it's type actually is. In case of dates, value if formatted according to format returned by {@link #getDateFormat()}. Binary and reference values are converted to empty string. In case of error during conversion, null will be returned instead.
260      */
261     public static String getValueString(Value value) {
262         try {
263             switch (value.getType()) {
264             case (PropertyType.STRING):
265                 return value.getString();
266             case (PropertyType.DOUBLE):
267                 return Double.toString(value.getDouble());
268             case (PropertyType.LONG):
269                 return Long.toString(value.getLong());
270             case (PropertyType.BOOLEAN):
271                 return Boolean.toString(value.getBoolean());
272             case (PropertyType.DATE):
273                 Date valueDate = value.getDate().getTime();
274             return DateUtil.format(valueDate, PropertyUtil.getDateFormat());
275             case (PropertyType.BINARY):
276                 // for lack of better solution, fall through to the default - empty string
277             default:
278                 return StringUtils.EMPTY;
279             }
280         } catch (RepositoryException e) {
281             log.debug("RepositoryException caught: " + e.getMessage(), e);
282         }
283         return null;
284 
285     }
286 
287     public static Value createValue(Object obj, ValueFactory valueFactory) throws RepositoryException {
288         switch (PropertyUtil.getJCRPropertyType(obj)) {
289         case PropertyType.STRING:
290             return valueFactory.createValue((String) obj);
291         case PropertyType.BOOLEAN:
292             return valueFactory.createValue((Boolean) obj);
293         case PropertyType.DATE:
294             return valueFactory.createValue((Calendar) obj);
295         case PropertyType.LONG:
296             return obj instanceof Long ? valueFactory.createValue(((Long) obj).longValue()) : valueFactory.createValue(((Integer) obj).longValue());
297         case PropertyType.DOUBLE:
298             return obj instanceof Double ? valueFactory.createValue((Double) obj) : valueFactory.createValue(((Float) obj).doubleValue());
299         case PropertyType.BINARY:
300             return valueFactory.createValue((InputStream) obj);
301         case PropertyType.REFERENCE:
302             return valueFactory.createValue(((Content) obj).getJCRNode());
303         default:
304             return (obj != null ? valueFactory.createValue(obj.toString()) : valueFactory.createValue(StringUtils.EMPTY));
305         }
306     }
307 
308     /**
309      * Return the Calendar representing the node property value.
310      * If the Node did not contain such a Property,
311      * then return <b>null</b>.
312      */
313     public static Calendar getDate(Node node, String name) {
314         return getDate(node, name, null);
315     }
316 
317     /**
318      * Return the Calendar representing the node property value.
319      * If the Node did not contain such a Property,
320      * then return the default value.
321      */
322     public static Calendar getDate(Node node, String name, Calendar defaultValue) {
323         try {
324             if (node.hasProperty(name)) {
325                 return node.getProperty(name).getDate();
326             }
327         } catch (RepositoryException e) {
328             log.error("can't read value '" + name + "' of the Node '" + node.toString() + "' will return default value", e);
329         }
330         return defaultValue;
331     }
332 
333     /**
334      * Return the String representing the node property value.
335      * If the Node did not contain such a Property,
336      * then return <b>null</b>.
337      */
338     public static String getString(Node node, String name) {
339         return getString(node, name, null);
340     }
341 
342     /**
343      * Return the String representing the node property value.
344      * If the Node did not contain such a Property,
345      * then return the default value.
346      */
347     public static String getString(Node node, String name, String defaultValue) {
348         try {
349             if (node.hasProperty(name)) {
350                 return node.getProperty(name).getString();
351             }
352         } catch (RepositoryException e) {
353             log.error("can't read value '" + name + "' of the Node '" + node.toString() + "' will return default value", e);
354         }
355         return defaultValue;
356     }
357 
358     /**
359      * Return the boolean representing the node property value.
360      * If the Node did not contain such a Property,
361      * then return the default value.
362      */
363     public static boolean getBoolean(Node node, String name, boolean defaultValue) {
364         try {
365             if (node.hasProperty(name)) {
366                 return node.getProperty(name).getBoolean();
367             }
368         } catch (RepositoryException e) {
369             log.error("can't read value '" + name + "' of the Node '" + node.toString() + "' will return default value", e);
370         }
371         return defaultValue;
372     }
373 
374     /**
375      * Return the Property relative to the Node.
376      * Return null in case of Exception.
377      */
378     public static Property getProperty(Node node, String relativePath) {
379         try {
380             return node.getProperty(relativePath);
381         }
382         catch (PathNotFoundException e) {
383             log.error("Property Access Exception ",e);
384         }
385         catch (RepositoryException e) {
386             log.error("Property Access Exception ",e);
387         }
388         return null;
389     }
390 
391 
392 }