View Javadoc

1   /*-------------------------------------------------------------------------
2    Copyright 2006 Olivier Berlanger
3   
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7   
8    http://www.apache.org/licenses/LICENSE-2.0
9   
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15   -------------------------------------------------------------------------*/
16  package net.sf.xolite;
17  
18  
19  import java.awt.Dimension;
20  import java.awt.Point;
21  import java.awt.Rectangle;
22  import java.text.DateFormat;
23  import java.text.ParseException;
24  import java.text.SimpleDateFormat;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.Date;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  
37  /**
38   * A helper class to get formatted value out of XML element attributes. <br>
39   * Note: this helper assume that attributes have no namespace (as it is usually the case). For the rare case where there is an
40   * attribute with namespace that has not a simple string value, you should get it directly from the XMLEventParser interface and
41   * interpret it with ad-hoc code.
42   * 
43   * @author Olivier Berlanger
44   */
45  public class Attributes {
46  
47  
48      private static Log log = LogFactory.getLog(Attributes.class);
49      private static ThreadLocal<Map<String, DateFormat>> threadDateFormats;
50  
51  
52      public static String getString(String attrName, String defaultValue, XMLEventParser parser) throws XMLParseException {
53          return getString(attrName, defaultValue, false, parser);
54      }
55  
56  
57      public static String getMandatoryString(String attrName, XMLEventParser parser) throws XMLParseException {
58          return getString(attrName, null, true, parser);
59      }
60  
61  
62      public static int getInt(String attrName, int defaultValue, XMLEventParser parser) throws XMLParseException {
63          return getInt(attrName, defaultValue, false, parser);
64      }
65  
66  
67      public static int getMandatoryInt(String attrName, XMLEventParser parser) throws XMLParseException {
68          return getInt(attrName, 0, true, parser);
69      }
70  
71  
72      public static <T extends Enum<T>> T getEnum(String attrName, T defaultValue, Class<T> enumType, XMLEventParser parser)
73              throws XMLParseException {
74          return getEnum(attrName, defaultValue, enumType, parser, false);
75      }
76  
77  
78      public static <T extends Enum<T>> T getMandatoryEnum(String attrName, Class<T> enumType, XMLEventParser parser)
79              throws XMLParseException {
80          return getEnum(attrName, null, enumType, parser, true);
81      }
82  
83  
84      public static double getDouble(String attrName, double defaultValue, XMLEventParser parser) throws XMLParseException {
85          return getDouble(attrName, defaultValue, false, parser);
86      }
87  
88  
89      public static double getMandatoryDouble(String attrName, XMLEventParser parser) throws XMLParseException {
90          return getDouble(attrName, 0, true, parser);
91      }
92  
93  
94      public static int[] getIntArray(String attrName, int[] defaultValue, XMLEventParser parser) throws XMLParseException {
95          return getIntArray(attrName, defaultValue, false, parser);
96      }
97  
98  
99      public static int[] getMandatoryIntArray(String attrName, XMLEventParser parser) throws XMLParseException {
100         return getIntArray(attrName, null, true, parser);
101     }
102 
103 
104     public static List<String> getStringList(String attrName, String separator, XMLEventParser parser) throws XMLParseException {
105         return getStringList(attrName, separator, false, parser);
106     }
107 
108 
109     public static List<String> getMandatoryStringList(String attrName, String separator, XMLEventParser parser)
110             throws XMLParseException {
111         return getStringList(attrName, separator, true, parser);
112     }
113 
114 
115     public static long getLong(String attrName, long defaultValue, XMLEventParser parser) throws XMLParseException {
116         return getLong(attrName, defaultValue, false, parser);
117     }
118 
119 
120     public static long getMandatoryLong(String attrName, XMLEventParser parser) throws XMLParseException {
121         return getLong(attrName, 0, true, parser);
122     }
123 
124 
125     public static boolean getBoolean(String attrName, boolean defaultValue, XMLEventParser parser) throws XMLParseException {
126         return getBoolean(attrName, defaultValue, false, parser);
127     }
128 
129 
130     public static boolean getMandatoryBoolean(String attrName, XMLEventParser parser) throws XMLParseException {
131         return getBoolean(attrName, false, true, parser);
132     }
133 
134 
135     public static Point getPoint(String attrName, Point defaultValue, XMLEventParser parser) throws XMLParseException {
136         return getPoint(attrName, defaultValue, false, parser);
137     }
138 
139 
140     public static Point getMandatoryPoint(String attrName, XMLEventParser parser) throws XMLParseException {
141         return getPoint(attrName, null, true, parser);
142     }
143 
144 
145     public static Dimension getDimension(String attrName, Dimension defaultValue, XMLEventParser parser)
146             throws XMLParseException {
147         return getDimension(attrName, defaultValue, false, parser);
148     }
149 
150 
151     public static Dimension getMandatoryDimension(String attrName, XMLEventParser parser) throws XMLParseException {
152         return getDimension(attrName, null, true, parser);
153     }
154 
155 
156     public static Rectangle getRectangle(String attrName, Rectangle defaultValue, XMLEventParser parser)
157             throws XMLParseException {
158         return getRectangle(attrName, defaultValue, false, parser);
159     }
160 
161 
162     public static Rectangle getMandatoryRectangle(String attrName, XMLEventParser parser) throws XMLParseException {
163         return getRectangle(attrName, null, true, parser);
164     }
165 
166 
167     public static Date getDate(String attrName, String pattern, Date defaultValue, XMLEventParser parser)
168             throws XMLParseException {
169         return getDate(attrName, pattern, defaultValue, false, parser);
170     }
171 
172 
173     public static Date getMandatoryDate(String attrName, String pattern, XMLEventParser parser) throws XMLParseException {
174         return getDate(attrName, pattern, null, true, parser);
175     }
176 
177 
178     // -------------------- Helper method for serialization ------------------------------------------------------------
179 
180 
181     public static final String intArrayToString(int[] values) {
182         if (values == null) return "";
183         StringBuffer sb = new StringBuffer();
184         int len = values.length;
185         for (int i = 0; i < len; i++) {
186             if (i > 0) sb.append(',');
187             sb.append(values[i]);
188         }
189         return sb.toString();
190     }
191 
192 
193     public static final String objectArrayToString(Object[] values) {
194         return iterableToString((values == null) ? null : Arrays.asList(values), ",", ";");
195     }
196 
197 
198     public static final String objectArrayToString(Object[] values, String separator, String replacement) {
199         return iterableToString((values == null) ? null : Arrays.asList(values), separator, replacement);
200     }
201 
202 
203     public static final String listToString(List<? extends Object> lst, String separator, String replacement) {
204         return iterableToString(lst, separator, replacement);
205     }
206 
207 
208     public static final String iterableToString(Iterable<? extends Object> iterabl, String separator, String replacement) {
209         String result = "";
210         if (iterabl != null) {
211             Iterator<? extends Object> it = iterabl.iterator();
212             if (it.hasNext()) {
213                 StringBuffer sb = new StringBuffer();
214                 sb.append(getNormalizedString(it.next(), separator, replacement));
215                 while (it.hasNext()) {
216                     sb.append(separator);
217                     sb.append(getNormalizedString(it.next(), separator, replacement));
218                 }
219                 result = sb.toString();
220             }
221         }
222         return result;
223     }
224 
225 
226     public static final String pointToString(Point pt) {
227         String result = "";
228         if (pt != null) {
229             StringBuffer sb = new StringBuffer();
230             sb.append(pt.x);
231             sb.append(',');
232             sb.append(pt.y);
233             result = sb.toString();
234         }
235         return result;
236     }
237 
238 
239     public static final String dimensionToString(Dimension dim) {
240         String result = "";
241         if (dim != null) {
242             StringBuffer sb = new StringBuffer();
243             sb.append(dim.width);
244             sb.append(',');
245             sb.append(dim.height);
246             result = sb.toString();
247         }
248         return result;
249     }
250 
251 
252     public static final String rectangleToString(Rectangle rect) {
253         String result = "";
254         if (rect != null) {
255             StringBuffer sb = new StringBuffer();
256             sb.append(rect.x);
257             sb.append(',');
258             sb.append(rect.y);
259             sb.append(',');
260             sb.append(rect.width);
261             sb.append(',');
262             sb.append(rect.height);
263             result = sb.toString();
264         }
265         return result;
266     }
267 
268 
269     public static final String dateToString(Date dat, String pattern) {
270         String result = "";
271         if (dat != null) {
272             DateFormat fmt = getDateFormat(pattern);
273             result = fmt.format(dat);
274         }
275         return result;
276     }
277 
278 
279     private static String getNormalizedString(Object value, String separator, String replacement) {
280         String valueString = (value == null) ? "null" : value.toString();
281         if (valueString.indexOf(separator) >= 0) {
282             log.warn("The string serialized into XML list <" + valueString + "> contains the list separator: '" + separator
283                     + "', will be replaced by '" + replacement + "'");
284             valueString = valueString.replace(separator, replacement);
285         }
286         return valueString;
287     }
288 
289 
290     // ----------------------- Implementation ---------------------------------------------------------
291 
292 
293     protected static String getAttributeRawValue(String attrName, boolean mandatory, XMLEventParser parser)
294             throws XMLParseException {
295         String attrVal = parser.getAttributeValue(attrName);
296         if ((attrVal == null) || (attrVal.length() == 0)) {
297             if (mandatory) {
298                 parser.throwParseException("Attribute '" + attrName + "' is mandatory", null);
299             }
300             attrVal = null;
301         }
302         return attrVal;
303     }
304 
305 
306     protected static String getString(String attrName, String defaultValue, boolean mandatory, XMLEventParser parser)
307             throws XMLParseException {
308         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
309         if (attrVal == null) attrVal = defaultValue;
310         return attrVal;
311     }
312 
313 
314     protected static boolean getBoolean(String attrName, boolean defaultValue, boolean mandatory, XMLEventParser parser)
315             throws XMLParseException {
316         boolean result = defaultValue;
317         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
318         if (attrVal != null) {
319             result = stringToBoolean(attrVal);
320         }
321         return result;
322     }
323 
324 
325     protected static int getInt(String attrName, int defaultValue, boolean mandatory, XMLEventParser parser)
326             throws XMLParseException {
327         int result = defaultValue;
328         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
329         if (attrVal != null) {
330             try {
331                 result = Integer.parseInt(attrVal);
332             } catch (Exception e) {
333                 parser.throwParseException("Attribute " + attrName + "='" + attrVal + "' must have an Integer value.", e);
334             }
335         }
336         return result;
337     }
338 
339 
340     protected static <T extends Enum<T>> T getEnum(String attrName, T defaultValue, Class<T> enumType, XMLEventParser parser,
341             boolean mandatory) throws XMLParseException {
342         T result = defaultValue;
343         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
344         if (attrVal != null) {
345             try {
346                 result = Enum.valueOf(enumType, attrVal);
347             } catch (Exception e) {
348                 parser.throwParseException("Attribute " + attrName + "='" + attrVal + "' must be a enum value of type "
349                         + enumType, e);
350             }
351         }
352         return result;
353     }
354 
355 
356     protected static double getDouble(String attrName, double defaultValue, boolean mandatory, XMLEventParser parser)
357             throws XMLParseException {
358         double result = defaultValue;
359         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
360         if (attrVal != null) {
361             try {
362                 result = Double.parseDouble(attrVal);
363             } catch (Exception e) {
364                 parser.throwParseException("Attribute " + attrName + "='" + attrVal + "' must have an Double value.", e);
365             }
366         }
367         return result;
368     }
369 
370 
371     protected static int[] getIntArray(String attrName, int[] defaultValue, boolean mandatory, XMLEventParser parser)
372             throws XMLParseException {
373         int[] result = defaultValue;
374         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
375         if (attrVal != null) {
376             try {
377                 result = stringToIntArray(attrVal);
378             } catch (Exception e) {
379                 parser.throwParseException("Attribute " + attrName + "='" + attrVal
380                         + "' must be a coma-separated list of integers", e);
381             }
382         }
383         return result;
384     }
385 
386 
387     protected static Dimension getDimension(String attrName, Dimension defaultValue, boolean mandatory, XMLEventParser parser)
388             throws XMLParseException {
389         Dimension result = defaultValue;
390         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
391         if (attrVal != null) {
392             try {
393                 int[] vals = stringToIntArray(attrVal);
394                 if (vals.length != 2) {
395                     throw new IllegalArgumentException("Bad dimension value --> it should be 2 integers, not " + vals.length);
396                 }
397                 result = new Dimension(vals[0], vals[1]);
398             } catch (Exception e) {
399                 parser.throwParseException("Attribute " + attrName + "='" + attrVal
400                         + "' must be a Dimension (coma-separated list of 2 integers)", e);
401             }
402         }
403         return result;
404     }
405 
406 
407     protected static Point getPoint(String attrName, Point defaultValue, boolean mandatory, XMLEventParser parser)
408             throws XMLParseException {
409         Point result = defaultValue;
410         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
411         if (attrVal != null) {
412             try {
413                 int[] vals = stringToIntArray(attrVal);
414                 if (vals.length != 2) {
415                     throw new IllegalArgumentException("Bad point value --> it should be 2 integers, not " + vals.length);
416                 }
417                 result = new Point(vals[0], vals[1]);
418             } catch (Exception e) {
419                 parser.throwParseException("Attribute " + attrName + "='" + attrVal
420                         + "' must be a Point (coma-separated list of 2 integers)", e);
421             }
422         }
423         return result;
424     }
425 
426 
427     protected static Rectangle getRectangle(String attrName, Rectangle defaultValue, boolean mandatory, XMLEventParser parser)
428             throws XMLParseException {
429         Rectangle result = defaultValue;
430         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
431         if (attrVal != null) {
432             try {
433                 int[] vals = stringToIntArray(attrVal);
434                 if (vals.length != 4) {
435                     throw new IllegalArgumentException("Bad rectangle value --> it should be 4 integers, not " + vals.length);
436                 }
437                 result = new Rectangle(vals[0], vals[1], vals[2], vals[3]);
438             } catch (Exception e) {
439                 parser.throwParseException("Attribute " + attrName + "='" + attrVal
440                         + "' must be a Rectangle (coma-separated list of 4 integers)", e);
441             }
442         }
443         return result;
444     }
445 
446 
447     protected static Date getDate(String attrName, String pattern, Date defaultValue, boolean mandatory, XMLEventParser parser)
448             throws XMLParseException {
449         Date result = defaultValue;
450         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
451         if (attrVal != null) {
452             try {
453                 DateFormat fmt = getDateFormat(pattern);
454                 result = fmt.parse(attrVal);
455             } catch (Exception e) {
456                 parser.throwParseException("Attribute " + attrName + "='" + attrVal + "' must be a Date with pattern ["
457                         + pattern + "]", e);
458             }
459         }
460         return result;
461     }
462 
463 
464     /**
465      * Method sharing the DateFormat used for parsing/formatting but ensuring that they are shared across threads (because they
466      * are not thread-safe).
467      */
468     protected static DateFormat getDateFormat(String pattern) {
469         Map<String, DateFormat> dateFormats = null;
470         synchronized (Attributes.class) {
471             if (threadDateFormats == null) threadDateFormats = new ThreadLocal<Map<String, DateFormat>>();
472             dateFormats = threadDateFormats.get();
473             if (dateFormats == null) {
474                 dateFormats = new HashMap<String, DateFormat>();
475                 threadDateFormats.set(dateFormats);
476             }
477         }
478         DateFormat fmt = dateFormats.get(pattern);
479         if (fmt == null) {
480             fmt = new SimpleDateFormat(pattern);
481             dateFormats.put(pattern, fmt);
482         }
483         return fmt;
484     }
485 
486 
487     /**
488      * Warning: This method return an unmodifiable list (not an instance of the usual ArrayList implementation).
489      * 
490      * @param attrName
491      *            The name of the attribute holding the list data in the current element of the parser.
492      * @param separator
493      *            The separator regular expression (see String.split(..))
494      * @param mandatory
495      *            Flag saying if this attribute is mandatory in its XML element.
496      * @param parser
497      *            The XML parser
498      * @return The content of the attribute as a list of string.
499      * @throws XMLParseException
500      *             if attribute is mandatory and not present or if parsing failed.
501      */
502     protected static List<String> getStringList(String attrName, String separator, boolean mandatory, XMLEventParser parser)
503             throws XMLParseException {
504         List<String> result = null;
505         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
506         if (attrVal != null) {
507             try {
508                 result = stringToStringList(attrVal, separator);
509             } catch (Exception e) {
510                 parser.throwParseException("Attribute " + attrName + "='" + attrVal
511                         + "' must be a coma-separated list of integers", e);
512             }
513         }
514         return result;
515     }
516 
517 
518     protected static long getLong(String attrName, long defaultValue, boolean mandatory, XMLEventParser parser)
519             throws XMLParseException {
520         long result = defaultValue;
521         String attrVal = getAttributeRawValue(attrName, mandatory, parser);
522         if (attrVal != null) {
523             try {
524                 result = Long.parseLong(attrVal);
525             } catch (Exception e) {
526                 parser.throwParseException("Attribute " + attrName + "='" + attrVal + "' must have an Long value.", e);
527             }
528         }
529         return result;
530     }
531 
532 
533     static final String trim(String str) {
534         return (str == null) ? null : str.trim();
535     }
536 
537 
538     static final boolean isEmpty(String src) {
539         if (src == null) return true;
540         int len = src.length();
541         for (int i = 0; i < len; i++) {
542             if (src.charAt(i) > 32) return false;
543         }
544         return true;
545     }
546 
547 
548     // ----------------- conversion methods String to Object -------------------------------------------------------
549 
550 
551     public static final boolean stringToBoolean(String value) {
552         if ((value == null) || (value.length() == 0)) return false;
553         char ch = value.charAt(0);
554         return ((ch == 'T') || (ch == 't') || (ch == '1'));
555     }
556 
557 
558     public static final int[] stringToIntArray(String value) {
559         if ((value == null) || (value.length() == 0)) return null;
560         String[] tokens = value.split(",");
561         int len = tokens.length;
562         int[] result = new int[len];
563         for (int i = 0; i < len; i++) {
564             result[i] = Integer.parseInt(tokens[i]);
565         }
566         return result;
567     }
568 
569 
570     /**
571      * Warning: This method return an unmodifiable list (not an instance of the usual ArrayList implementation).
572      * 
573      * @param src
574      *            The string to transform to a List.
575      * @param separator
576      *            The list items separator.
577      * @return The content of the given string as a List.
578      */
579     public static final List<String> stringToStringList(String src, String separator) {
580         List<String> result;
581         if ((src != null) && (src.length() > 0)) {
582             String[] splitted = src.split(separator);
583             result = Arrays.asList(splitted);
584         } else {
585             result = Collections.emptyList();
586         }
587         return result;
588     }
589 
590 
591     public static final String stringListToString(List<String> list, String separator) {
592         StringBuilder sb = new StringBuilder();
593         int len = (list == null) ? 0 : list.size();
594         for (int i = 0; i < len; i++) {
595             if (i > 0) sb.append(separator);
596             sb.append(list.get(i));
597         }
598         return sb.toString();
599     }
600 
601 
602     public static final Date stringToDate(String src, String pattern) throws ParseException {
603         Date result = null;
604         if ((src != null) && (src.length() > 0)) {
605             DateFormat fmt = getDateFormat(pattern);
606             result = fmt.parse(src);
607         }
608         return result;
609     }
610 
611 }