KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > Casting


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10
11 package org.mmbase.util;
12
13 /**
14  * Collects MMBase specific 'cast' information, as static to... functions. This is used (and used to
15  * be implemented) in MMObjectNode. But this functionality is more generic to MMbase.
16  *
17  * @author Michiel Meeuwissen
18  * @since MMBase-1.6
19  * @version $Id: Casting.java,v 1.89 2006/07/26 09:08:01 michiel Exp $
20  */

21
22 import java.util.*;
23 import java.text.*;
24 import java.io.*;
25 import javax.xml.parsers.*;
26 import javax.xml.transform.*;
27 import org.mmbase.bridge.Node;
28 import org.mmbase.bridge.Cloud;
29 import org.mmbase.bridge.ContextProvider;
30 import org.mmbase.bridge.util.NodeWrapper;
31 import org.mmbase.bridge.util.NodeMap;
32 import org.mmbase.bridge.util.MapNode;
33 import org.mmbase.util.transformers.CharTransformer;
34 import org.mmbase.util.logging.*;
35 import org.mmbase.util.xml.XMLWriter;
36
37 import org.w3c.dom.*;
38
39 public class Casting {
40
41     /**
42      * A Date formatter that creates a date based on a ISO 8601 date and a ISO 8601 time.
43      * I.e. 2004-12-01 14:30:00.
44      * It is NOT 100% ISO 8601, as opposed to {@link #ISO_8601_UTC}, as the standard actually requires
45      * a 'T' to be placed between the date and the time.
46      * The date given is the date for the local (server) time. Use this formatter if you want to display
47      * user-friendly dates in local time.
48
49      * XXX: According to http://en.wikipedia.org/wiki/ISO_8601, the standard allows ' ' in stead of
50      * 'T' if no misunderstanding arises, which is the case here. So I don't think this is 'loose'.
51      */

52     public final static DateFormat ISO_8601_LOOSE = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
53
54     /**
55      * A Date formatter that creates a ISO 8601 datetime according to UTC/GMT.
56      * I.e. 2004-12-01T14:30:00Z.
57      * This is 100% ISO 8601, as opposed to {@link #ISO_8601_LOOSE}.
58      * Use this formatter if you want to export dates.
59      *
60      * XXX: Hmm, we parse with UTC now, while we don't store them as such.
61      */

62     public final static DateFormat ISO_8601_UTC = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
63     static {
64         ISO_8601_UTC.setTimeZone(TimeZone.getTimeZone("UTC"));
65     }
66
67     public final static DateFormat ISO_8601_DATE = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
68     public final static DateFormat ISO_8601_TIME = new SimpleDateFormat("HH:mm:ss", Locale.US);
69
70
71
72     private static final Logger log = Logging.getLoggerInstance(Casting.class);
73
74     /**
75      * Returns whether the passed object is of the given class.
76      * Unlike Class instanceof this also includes Object Types that
77      * are representative for primitive types (i.e. Integer for int).
78      * @param type the type (class) to check
79      * @param value the value whose type to check
80      * @return <code>true</code> if compatible
81      * @since MMBase-1.8
82      */

83     public static boolean isType(Class JavaDoc type, Object JavaDoc value) {
84         if (type.isPrimitive()) {
85             return (type.equals(Boolean.TYPE) && value instanceof Boolean JavaDoc) ||
86                    (type.equals(Byte.TYPE) && value instanceof Byte JavaDoc) ||
87                    (type.equals(Character.TYPE) && value instanceof Character JavaDoc) ||
88                    (type.equals(Short.TYPE) && value instanceof Short JavaDoc) ||
89                    (type.equals(Integer.TYPE) && value instanceof Integer JavaDoc) ||
90                    (type.equals(Long.TYPE) && value instanceof Long JavaDoc) ||
91                    (type.equals(Float.TYPE) && value instanceof Float JavaDoc) ||
92                    (type.equals(Double.TYPE) && value instanceof Double JavaDoc);
93         } else {
94             return value == null || type.isInstance(value);
95         }
96     }
97
98     /**
99      * Tries to 'cast' an object for use with the provided class. E.g. if value is a String, but the
100      * type passed is Integer, then the string is act to an Integer.
101      * If the type passed is a primitive type, the object is cast to an Object Types that is representative
102      * for that type (i.e. Integer for int).
103      * @param type the type (class)
104      * @param value The value to be converted
105      * @return value the converted value
106      * @since MMBase-1.8
107      */

108     public static Object JavaDoc toType(Class JavaDoc type, Object JavaDoc value) {
109         return toType(type, null, value);
110     }
111
112     private static Cloud anonymousCloud = null;
113
114     /**
115      * Tries to 'cast' an object for use with the provided class. E.g. if value is a String, but the
116      * type passed is Integer, then the string is act to an Integer.
117      * If the type passed is a primitive type, the object is cast to an Object Types that is representative
118      * for that type (i.e. Integer for int).
119      * @param type the type (class)
120      * @param cloud When casting to Node, a cloud may be needed. May be <code>null</code>, for an anonymous cloud to be tried.
121      * @param value The value to be converted
122      * @return value the converted value
123      * @since MMBase-1.8
124      */

125     public static Object JavaDoc toType(Class JavaDoc type, Cloud cloud, Object JavaDoc value) {
126         if (value != null && isType(type, value)) {
127             return value;
128         } else {
129             if (type.equals(Boolean.TYPE) || type.equals(Boolean JavaDoc.class)) {
130                 return Boolean.valueOf(toBoolean(value));
131             } else if (type.equals(Byte.TYPE) || type.equals(Byte JavaDoc.class)) {
132                 return new Byte JavaDoc(toInteger(value).byteValue());
133             } else if (type.equals(Character.TYPE) || type.equals(Character JavaDoc.class)) {
134                 String JavaDoc chars = toString(value);
135                 if (chars.length() > 0) {
136                     return new Character JavaDoc(chars.charAt(0));
137                 } else {
138                     return new Character JavaDoc(Character.MIN_VALUE);
139                 }
140             } else if (type.equals(Short.TYPE) || type.equals(Short JavaDoc.class)) {
141                 return new Short JavaDoc(toInteger(value).shortValue());
142             } else if (type.equals(Integer.TYPE) || type.equals(Integer JavaDoc.class)) {
143                 return toInteger(value);
144             } else if (type.equals(Long.TYPE) || type.equals(Long JavaDoc.class)) {
145                 return new Long JavaDoc(toLong(value));
146             } else if (type.equals(Float.TYPE) || type.equals(Float JavaDoc.class)) {
147                 return new Float JavaDoc(toFloat(value));
148             } else if (type.equals(Double.TYPE) || type.equals(Double JavaDoc.class)) {
149                 return new Double JavaDoc(toDouble(value));
150             } else if (type.equals(Number JavaDoc.class)) {
151                 Number JavaDoc res;
152                 try {
153                     res = new Long JavaDoc("" + value);
154                 } catch (NumberFormatException JavaDoc nfe) {
155                     try {
156                         res = new Double JavaDoc("" + value);
157                     } catch (NumberFormatException JavaDoc nfe1) {
158                         res = new Integer JavaDoc(-1);
159                     }
160                 }
161                 return res;
162             } else if (type.equals(byte[].class)) {
163                 return toByte(value);
164             } else if (type.equals(String JavaDoc.class)) {
165                 return toString(value);
166             } else if (type.equals(Date.class)) {
167                 return toDate(value);
168             } else if (type.equals(Node.class)) {
169                 try {
170                     if (cloud == null) {
171                         if (anonymousCloud == null) anonymousCloud = ContextProvider.getDefaultCloudContext().getCloud("mmbase");
172                         cloud = anonymousCloud;
173                     }
174                     return toNode(value, cloud);
175                 } catch (Exception JavaDoc e) {
176                     // suppose that that was because mmbase not running
177
return value instanceof Node ? value : null;
178                 }
179             } else if (type.equals(Document.class)) {
180                 return toXML(value);
181             } else if (type.equals(List.class)) {
182                 return toList(value);
183             } else if (type.equals(Map.class)) {
184                 return toMap(value);
185             } else if (type.equals(Collection.class)) {
186                 return toCollection(value);
187             } else {
188                 if (value == null || "".equals(value)) {
189                     // just to avoid the error
190
return null;
191                 }
192                 log.error("Dont now how to convert to " + type);
193                 // don't know
194
return value;
195             }
196         }
197     }
198
199     /**
200      * Whether or not Casting can more or less reliably cast a certain type to String and back.
201      * For collection types also the entries of the collection must be string representable.
202      * @since MMBase-1.8
203      */

204     public static boolean isStringRepresentable(Class JavaDoc type) {
205         return
206             CharSequence JavaDoc.class.isAssignableFrom(type) ||
207             Number JavaDoc.class.isAssignableFrom(type) ||
208             Boolean.TYPE.isAssignableFrom(type) ||
209             Boolean JavaDoc.class.isAssignableFrom(type) ||
210             Character JavaDoc.class.isAssignableFrom(type) ||
211             Node.class.isAssignableFrom(type) ||
212             Document.class.isAssignableFrom(type) ||
213             Collection.class.isAssignableFrom(type) ||
214             Map.class.isAssignableFrom(type);
215     }
216
217     /**
218      * Convert an object to a String.
219      * 'null' is converted to an empty string.
220      * @param o the object to convert
221      * @return the converted value as a <code>String</code>
222      */

223     public static String JavaDoc toString(Object JavaDoc o) {
224         if (o instanceof String JavaDoc) {
225             return (String JavaDoc)o;
226         }
227         if (o == null || "".equals(o)) {
228             return "";
229         }
230
231         return toStringBuffer(new StringBuffer JavaDoc(), o).toString();
232     }
233
234     /**
235      * Convert an object to a string, using a StringBuffer.
236      * @param buffer The StringBuffer with which to create the string
237      * @param o the object to convert
238      * @return the StringBuffer used for conversion (same as the buffer parameter)
239      * @since MMBase-1.7
240      */

241     public static StringBuffer JavaDoc toStringBuffer(StringBuffer JavaDoc buffer, Object JavaDoc o) {
242         if (o == null) {
243             return buffer;
244         }
245         try {
246             toWriter(new StringBufferWriter(buffer), o);
247         } catch (java.io.IOException JavaDoc e) {}
248         return buffer;
249     }
250
251     /**
252      * Convert an object to a string, using a Writer.
253      * @param writer The Writer with which to create (write) the string
254      * @param o the object to convert
255      * @return the Writer used for conversion (same as the writer parameter)
256      * @since MMBase-1.7
257      */

258     public static Writer toWriter(Writer writer, Object JavaDoc o) throws java.io.IOException JavaDoc {
259         if (o instanceof Writer) {
260             return writer;
261         }
262         Object JavaDoc s = wrap(o, null);
263         writer.write(s.toString());
264         return writer;
265     }
266
267     /**
268      * Wraps it in an object with a toString as we desire. Casting can now be done with
269      * toString() on the resulting object.
270      *
271      * This is used to make JSTL en EL behave similarly as mmbase taglib when writing objects to the
272      * page (taglib calls Casting, but they of course don't).
273      *
274      * @todo Not everything is wrapped (and can be unwrapped) already.
275      * @param o The object to be wrapped
276      * @param escaper <code>null</code> or a CharTransformer to pipe the strings through
277      * @since MMBase-1.8
278      */

279
280     public static Object JavaDoc wrap(final Object JavaDoc o, final CharTransformer escaper) {
281         if (o == null) {
282             return escape(escaper, "");
283         } else if (o instanceof Node) {
284             return new NodeMap((Node)o) {
285                     public Object JavaDoc getValue(String JavaDoc fieldName) {
286                         switch(getNodeManager().getField(fieldName).getType()) {
287                         case org.mmbase.bridge.Field.TYPE_NODE: return wrap(getNodeValue(fieldName), escaper);
288                         case org.mmbase.bridge.Field.TYPE_DATETIME: return wrap(getDateValue(fieldName), escaper);
289                         case org.mmbase.bridge.Field.TYPE_XML: return wrap(getXMLValue(fieldName), escaper);
290                         default: return escape(escaper, super.getStringValue(fieldName));
291                         }
292                     }
293                     public String JavaDoc toString() {
294                         return escape(escaper, "" + node.getNumber());
295                     }
296                 };
297         } else if (o instanceof Date) {
298             return new java.util.Date JavaDoc(((Date)o).getTime()) {
299                     private static final long serialVersionUID = 1L; // increase this if object chages.
300
public String JavaDoc toString() {
301                         long time = getTime();
302                         return time == -1 ? ("" + time) : ("" + time / 1000);
303                     }
304                 };
305         } else if (o instanceof org.w3c.dom.Node JavaDoc) {
306             // don't know how to wrap
307
return escape(escaper, XMLWriter.write((org.w3c.dom.Node JavaDoc) o, false, true));
308         } else if (o instanceof List) {
309             return new ListWrapper((List) o, escaper);
310         } else if (o instanceof byte[]) {
311             return escape(escaper, new String JavaDoc((byte[])o));
312         } else if (o instanceof String JavaDoc) {
313             return escape(escaper, (String JavaDoc) o);
314         } else if (o instanceof CharSequence JavaDoc) {
315             return new StringWrapper((CharSequence JavaDoc) o, escaper);
316         } else {
317             return o;
318         }
319
320
321     }
322
323     private static String JavaDoc escape(CharTransformer escaper, CharSequence JavaDoc string) {
324         if (escaper != null) {
325             return escaper.transform(string.toString());
326         } else {
327             return string.toString();
328         }
329     }
330     /**
331      * When you want to undo the wrapping, this method can be used.
332      * @since MMBase-1.8
333      */

334     public static Object JavaDoc unWrap(final Object JavaDoc o) {
335         if (o instanceof NodeWrapper) {
336             return ((NodeWrapper)o).getNode();
337         } else if (o instanceof ListWrapper) {
338             return ((ListWrapper)o).getList();
339         } else if (o instanceof StringWrapper) {
340             return ((StringWrapper)o).getString();
341         } else {
342             return o;
343         }
344     }
345
346     /**
347      * Convert an object to a List.
348      * A String is split up (as if it was a comma-separated String).
349      * Individual objects are wrapped and returned as Lists with one item.
350      * <code>null</code> and the empty string are returned as an empty list.
351      * @param o the object to convert
352      * @return the converted value as a <code>List</code>
353      * @since MMBase-1.7
354      */

355     public static List toList(Object JavaDoc o) {
356         return toList(o, ",");
357     }
358
359     /**
360      * As {@link #toList(Object)} but with one extra argument.
361      *
362      * @param delimiter Regexp to use when splitting up the string if the object is a String. <code>null</code> or the empty string mean the default, which is a comma.
363      * @since MMBase-1.8
364      */

365     public static List toList(Object JavaDoc o, String JavaDoc delimiter) {
366         if (o instanceof List) {
367             return (List)o;
368         } else if (o instanceof Collection) {
369             return new ArrayList((Collection) o);
370         } else if (o instanceof String JavaDoc) {
371             if ("".equals(delimiter) || delimiter == null) delimiter = ",";
372             return StringSplitter.split((String JavaDoc)o, delimiter);
373         } else if (o instanceof Map) {
374             return new ArrayList(((Map)o).entrySet());
375         } else {
376             List l = new ArrayList();
377             if (o != null) {
378                 l.add(o);
379             }
380             return l;
381         }
382     }
383
384
385     /**
386      * @since MMBase-1.8
387      */

388     public static Map toMap(Object JavaDoc o) {
389         if (o instanceof Map) {
390             return (Map) o;
391         } else if (o instanceof org.mmbase.util.functions.Parameters) {
392             return ((org.mmbase.util.functions.Parameters) o).toMap();
393         } else if (o instanceof Collection) {
394             Map result = new HashMap();
395             Iterator i = ((Collection)o).iterator();
396             while (i.hasNext()) {
397                 Object JavaDoc n = i.next();
398                 if (n instanceof Map.Entry) {
399                     Map.Entry entry = (Map.Entry) n;
400                     result.put(entry.getKey(), entry.getValue());
401                 } else {
402                     result.put(n, n);
403                 }
404             }
405             return result;
406         } else if (o instanceof Node) {
407             return new NodeMap((Node)o);
408         } else {
409             Map m = new HashMap();
410             m.put(o, o);
411             return m;
412         }
413     }
414
415     /**
416      * Transforms an object to a collection. If the object is a collection already, then nothing
417      * happens. If it is a Map, then the 'entry set' is returned. A string is interpreted as a
418      * comma-separated list of strings. Other objects are wrapped in an ArrayList with one element.
419      *
420      * @since MMBase-1.8
421      */

422     public static Collection toCollection(Object JavaDoc o) {
423         if (o instanceof Collection) {
424             return (Collection)o;
425         } else if (o instanceof Map) {
426             return ((Map)o).entrySet();
427         } else if (o instanceof String JavaDoc) {
428             return StringSplitter.split((String JavaDoc)o);
429         } else {
430             List l = new ArrayList();
431             if (o != null) {
432                 l.add(o);
433             }
434             return l;
435         }
436     }
437
438     /**
439      * Convert the value to a <code>Document</code> object.
440      * If the value is not itself a Document, the method attempts to
441      * attempts to convert the String value into an XML.
442      * A <code>null</code> value is returned as <code>null</code>.
443      * If the value cannot be converted, this method throws an IllegalArgumentException.
444      * @param o the object to be converted to an XML document
445      * @return the value as a DOM Element or <code>null</code>
446      * @throws IllegalArgumentException if the value could not be converted
447      * @since MMBase-1.6
448      */

449     static public Document toXML(Object JavaDoc o) {
450         if (o == null) return null;
451         if (!(o instanceof Document)) {
452             //do conversion from String to Document...
453
// This is a laborous action, so we log it on debug.
454
// It will happen often if the nodes are not cached and so on.
455
String JavaDoc xmltext = toString(o);
456             if (log.isDebugEnabled()) {
457                 String JavaDoc msg = xmltext;
458                 if (msg.length() > 84) {
459                     msg = msg.substring(0, 80) + "...";
460                 }
461                 log.debug("Object '" + msg + "' is not a Document, but a " + o.getClass().getName() + "");
462             }
463             return convertStringToXML(xmltext);
464         }
465         return (Document)o;
466     }
467
468     /**
469      * Convert an object to a byte array.
470      * @param obj The object to be converted
471      * @return the value as an <code>byte[]</code> (binary/blob field)
472      */

473     static public byte[] toByte(Object JavaDoc obj) {
474         if (obj == null) {
475             return new byte[] {};
476         } else if (obj instanceof byte[]) {
477             // was allready unmapped so return the value
478
return (byte[])obj;
479         } else if (obj instanceof org.apache.commons.fileupload.FileItem) {
480             return ((org.apache.commons.fileupload.FileItem) obj).get();
481         } else {
482             return toString(obj).getBytes();
483         }
484     }
485
486     static public InputStream toInputStream(Object JavaDoc obj) {
487         if (obj instanceof InputStream) {
488             return (InputStream) obj;
489         } else {
490             return new ByteArrayInputStream(toByte(obj));
491         }
492     }
493
494
495     /**
496      * Convert an object to an Node.
497      * If the value is Numeric, the method
498      * tries to obtrain the object with that number.
499      * If it is a String, the method tries to obtain the object with
500      * that alias.
501      * All remaining situations return <code>null</code>.
502      * @param i the object to convert
503      * @param cloud the Cloud to use for loading a node
504      * @return the value as a <code>Node</code>
505      * @since MMBase-1.7
506      */

507     public static Node toNode(Object JavaDoc i, Cloud cloud) {
508         Node res = null;
509         if (i instanceof Node) {
510             res = (Node)i;
511         } else if (i instanceof Number JavaDoc) {
512             int nodenumber = ((Number JavaDoc)i).intValue();
513             if (nodenumber != -1) {
514                 res = cloud.getNode(nodenumber);
515             }
516         } else if (i instanceof Map) {
517             res = new MapNode((Map)i, cloud);
518         } else if (i != null && !i.equals("")) {
519             res = cloud.getNode(i.toString());
520         }
521         return res;
522     }
523
524     /**
525      * Convert an object to an <code>int</code>.
526      * Boolean values return 0 for false, 1 for true.
527      * String values are parsed to a number, if possible.
528      * If a value is an Node, it's number field is returned.
529      * All remaining values return the provided default value.
530      * @param i the object to convert
531      * @param def the default value if conversion is impossible
532      * @return the converted value as an <code>int</code>
533      * @since MMBase-1.7
534      */

535     static public int toInt(Object JavaDoc i, int def) {
536         int res = def;
537         if (i instanceof Node) {
538             res = ((Node)i).getNumber();
539         } else if (i instanceof Boolean JavaDoc) {
540             res = ((Boolean JavaDoc)i).booleanValue() ? 1 : 0;
541         } else if (i instanceof Date) {
542             long timeValue = ((Date)i).getTime();
543             if (timeValue !=-1) timeValue = timeValue / 1000;
544             if (timeValue > Integer.MAX_VALUE) {
545                 timeValue = Integer.MAX_VALUE;
546             }
547             if (timeValue < Integer.MIN_VALUE) {
548                 timeValue = Integer.MIN_VALUE;
549             }
550             res = (int) timeValue;
551         } else if (i instanceof Number JavaDoc) {
552             long l = ((Number JavaDoc)i).longValue();
553             if (l > Integer.MAX_VALUE) {
554                 res = Integer.MAX_VALUE;
555             } else if (l < Integer.MIN_VALUE) {
556                 res = Integer.MIN_VALUE;
557             } else {
558                 res = (int) l;
559             }
560         } else if (i != null) {
561             try {
562                 res = Integer.parseInt("" + i);
563             } catch (NumberFormatException JavaDoc e) {
564                 // not an integer? perhaps it is a fload or double represented as String.
565
try {
566                     res = Double.valueOf("" + i).intValue();
567                 } catch (NumberFormatException JavaDoc ex) {
568
569                     // try if the value is a string representing a boolean.
570
if(i instanceof String JavaDoc){
571                         if(((String JavaDoc)i).toLowerCase().equals(("true"))){
572                             res = 1;
573                         }else if(((String JavaDoc)i).toLowerCase().equals(("false"))){
574                             res = 0;
575                         }
576                     }
577                 }
578             }
579         }
580         return res;
581     }
582
583     /**
584      * Convert an object to an <code>int</code>.
585      * Boolean values return 0 for false, 1 for true.
586      * String values are parsed to a number, if possible.
587      * If a value is a Node, it's number field is returned.
588      * All remaining values return -1.
589      * @param i the object to convert
590      * @return the converted value as an <code>int</code>
591      */

592     static public int toInt(Object JavaDoc i) {
593         return toInt(i, -1);
594     }
595
596
597
598     /**
599      * Convert an object to a <code>boolean</code>.
600      * If the value is numeric, this call returns <code>true</code>
601      * if the value is a positive, non-zero, value. In other words, values '0'
602      * and '-1' are considered <code>false</code>.
603      * If the value is a string, this call returns <code>true</code> if
604      * the value is "true" or "yes" (case-insensitive).
605      * In all other cases (including calling byte fields), <code>false</code>
606      * is returned.
607      * @param b the object to convert
608      * @return the converted value as a <code>boolean</code>
609      */

610     static public boolean toBoolean(Object JavaDoc b) {
611         if (b == null) {
612             return false;
613         } else if (b instanceof Boolean JavaDoc) {
614             return ((Boolean JavaDoc)b).booleanValue();
615         } else if (b instanceof Number JavaDoc) {
616             return ((Number JavaDoc)b).doubleValue() > 0;
617         } else if (b instanceof Node) {
618             return true; // return true if a NODE is filled
619
} else if (b instanceof Date) {
620             return ((Date)b).getTime() != -1;
621         } else if (b instanceof Document) {
622             return false; // undefined
623
} else if (b instanceof String JavaDoc) {
624             // note: we don't use Boolean.valueOf() because that only captures
625
// the value "true"
626
String JavaDoc s = ((String JavaDoc)b).toLowerCase();
627             return s.equals("true") || s.equals("yes") || s.equals("1");
628         } else {
629             return false;
630         }
631     }
632
633     /**
634      * Convert an object to an Integer.
635      * Boolean values return 0 for false, 1 for true.
636      * String values are parsed to a number, if possible.
637      * All remaining values return -1.
638      * @param i the object to convert
639      * @return the converted value as a <code>Integer</code>
640      */

641     static public Integer JavaDoc toInteger(Object JavaDoc i) {
642         if (i instanceof Integer JavaDoc) {
643             return (Integer JavaDoc)i;
644         } else {
645             return new Integer JavaDoc(toInt(i));
646         }
647     }
648
649     /**
650      * Convert an object to a <code>long</code>.
651      * Boolean values return 0 for false, 1 for true.
652      * String values are parsed to a number, if possible.
653      * All remaining values return the provided default value.
654      * @param i the object to convert
655      * @param def the default value if conversion is impossible
656      * @return the converted value as a <code>long</code>
657      * @since MMBase-1.7
658      */

659     static public long toLong(Object JavaDoc i, long def) {
660         long res = def;
661         if (i instanceof Boolean JavaDoc) {
662             res = ((Boolean JavaDoc)i).booleanValue() ? 1 : 0;
663         } else if (i instanceof Number JavaDoc) {
664             res = ((Number JavaDoc)i).longValue();
665         } else if (i instanceof Date) {
666             res = ((Date)i).getTime();
667             if (res !=- 1) res /= 1000;
668         } else if (i instanceof Node) {
669             res = ((Node)i).getNumber();
670         } else if (i != null) {
671             if(i instanceof String JavaDoc){
672                 if(((String JavaDoc)i).toLowerCase().equals("true")) return 1;
673                 if(((String JavaDoc)i).toLowerCase().equals("false")) return 0;
674             }
675             try {
676                 res = Long.parseLong("" + i);
677             } catch (NumberFormatException JavaDoc e) {
678                 // not an integer? perhaps it is a float or double represented as String.
679
try {
680                     res = Double.valueOf("" + i).longValue();
681                 } catch (NumberFormatException JavaDoc ex) {
682                     // give up, fall back to default.
683
}
684             }
685         }
686         return res;
687     }
688
689     /**
690      * Convert an object to a <code>long</code>.
691      * Boolean values return 0 for false, 1 for true.
692      * String values are parsed to a number, if possible.
693      * All remaining values return -1.
694      * @param i the object to convert
695      * @return the converted value as a <code>long</code>
696      * @since MMBase-1.7
697      */

698     static public long toLong(Object JavaDoc i) {
699         return toLong(i, -1);
700     }
701
702     /**
703      * Convert an object to an <code>float</code>.
704      * Boolean values return 0 for false, 1 for true.
705      * String values are parsed to a number, if possible.
706      * All remaining values return the default value.
707      * @param i the object to convert
708      * @param def the default value if conversion is impossible
709      * @return the converted value as a <code>float</code>
710      */

711     static public float toFloat(Object JavaDoc i, float def) {
712         float res = def;
713         if (i instanceof Boolean JavaDoc) {
714             res = ((Boolean JavaDoc)i).booleanValue() ? 1 : 0;
715         } else if (i instanceof Number JavaDoc) {
716             res = ((Number JavaDoc)i).floatValue();
717         } else if (i instanceof Date) {
718             res = ((Date)i).getTime();
719             if (res!=-1) res = res / 1000;
720         } else if (i instanceof Node) {
721             res = ((Node)i).getNumber();
722         } else if (i != null) {
723             if(i instanceof String JavaDoc){
724                 if(((String JavaDoc)i).toLowerCase().equals("true")) {
725                     res = 1;
726                 } else if(((String JavaDoc)i).toLowerCase().equals("false")) {
727                     res = 0;
728                 }
729             }
730             try {
731                 res = Float.parseFloat("" + i);
732             } catch (NumberFormatException JavaDoc e) {
733 // try if the value is a string representing a boolean.
734
if(i instanceof String JavaDoc){
735                     if(((String JavaDoc)i).toLowerCase().equals(("true"))){
736                         res = 1;
737                     } else if(((String JavaDoc)i).toLowerCase().equals(("false"))){
738                         res = 0;
739                     }
740                 }
741             }
742         }
743         return res;
744     }
745
746     /**
747      * Convert an object to an <code>float</code>.
748      * Boolean values return 0 for false, 1 for true.
749      * String values are parsed to a number, if possible.
750      * All remaining values return -1.
751      * @param i the object to convert
752      * @return the converted value as a <code>float</code>
753      */

754     static public float toFloat(Object JavaDoc i) {
755         return toFloat(i, -1);
756     }
757
758     /**
759      * Convert an object to an <code>double</code>.
760      * Boolean values return 0 for false, 1 for true.
761      * String values are parsed to a number, if possible.
762      * All remaining values return the default value.
763      * @param i the object to convert
764      * @param def the default value if conversion is impossible
765      * @return the converted value as a <code>double</code>
766      */

767     static public double toDouble(Object JavaDoc i, double def) {
768         double res = def;
769         if (i instanceof Boolean JavaDoc) {
770             res = ((Boolean JavaDoc)i).booleanValue() ? 1 : 0;
771         } else if (i instanceof Number JavaDoc) {
772             res = ((Number JavaDoc)i).doubleValue();
773         } else if (i instanceof Date) {
774             res = ((Date)i).getTime();
775             if (res != -1) res = res / 1000;
776         } else if (i instanceof Node) {
777             res = ((Node)i).getNumber();
778         } else if (i != null) {
779             try {
780                 res = Double.parseDouble("" + i);
781             } catch (NumberFormatException JavaDoc e) {
782 // try if the value is a string representing a boolean.
783
if(i instanceof String JavaDoc){
784                     if(((String JavaDoc)i).toLowerCase().equals(("true"))){
785                         res = 1;
786                     }else if(((String JavaDoc)i).toLowerCase().equals(("false"))){
787                         res = 0;
788                     }
789                 }
790             }
791         }
792         return res;
793     }
794
795     /**
796      * Convert an object to an <code>double</code>.
797      * Boolean values return 0 for false, 1 for true.
798      * String values are parsed to a number, if possible.
799      * All remaining values return -1.
800      * @param i the object to convert
801      * @return the converted value as a <code>double</code>
802      */

803     static public double toDouble(Object JavaDoc i) {
804         return toDouble(i, -1);
805     }
806
807
808
809     /**
810      * Convert an object to a <code>Date</code>.
811      * String values are parsed to a date, if possible.
812      * Numeric values are assumed to represent number of seconds since 1970.
813      * All remaining values return 1969-12-31 23:59 GMT.
814      * @param d the object to convert
815      * @return the converted value as a <code>Date</code>, never <code>null</code>
816      * @since MMBase-1.7
817      */

818     static public Date toDate(Object JavaDoc d) {
819         if (d == null) return new Date(-1);
820         Date date = null;
821
822         if (d instanceof Date) {
823             date = (Date) d;
824         } else {
825             try {
826                 long dateInSeconds = -1;
827                 if (d instanceof Number JavaDoc) {
828                     dateInSeconds = ((Number JavaDoc)d).longValue();
829                 } else if (d instanceof Document) {
830                     // impossible
831
dateInSeconds = -1;
832                 } else if (d instanceof Boolean JavaDoc) {
833                     dateInSeconds = -1;
834                 } else if (d instanceof Collection) {
835                     // impossible
836
dateInSeconds = -1;
837                 } else if (d instanceof Node) {
838                     // impossible
839
dateInSeconds = -1;
840                 } else if (d != null) {
841                     d = toString(d);
842                     if (d.equals("")) {
843                         return new Date(-1);
844                     }
845                     dateInSeconds = Long.parseLong((String JavaDoc) d);
846                 } else {
847                     dateInSeconds = -1;
848                 }
849                 if (dateInSeconds == -1) {
850                     date = new Date(-1);
851                 } else if (dateInSeconds > Long.MAX_VALUE / 1000) {
852                     date = new Date(Long.MAX_VALUE); // or should this throw an exception?
853
} else if (dateInSeconds < Long.MIN_VALUE / 1000) {
854                     date = new Date(Long.MIN_VALUE); // or should this throw an exception?
855
} else {
856                     date = new Date(dateInSeconds * 1000);
857                 }
858             } catch (NumberFormatException JavaDoc e) {
859                 try {
860                     date = DynamicDate.getInstance((String JavaDoc) d);
861                 } catch (org.mmbase.util.dateparser.ParseException pe) {
862                     log.error("Parser exception in " + d, pe);
863                     return new Date(-1);
864                 } catch (Error JavaDoc per) {
865                     throw new Error JavaDoc("Parser error in " + d, per);
866                 }
867             }
868         }
869         return date;
870     }
871
872     static DocumentBuilder DOCUMENTBUILDER;
873     static {
874         try {
875             DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
876             dfactory.setValidating(false);
877             dfactory.setNamespaceAware(true);
878             DOCUMENTBUILDER = dfactory.newDocumentBuilder();
879             DOCUMENTBUILDER.setEntityResolver(new XMLEntityResolver(false));
880         } catch (ParserConfigurationException pce) {
881             log.error("[sax parser]: " + pce.toString() + "\n" + Logging.stackTrace(pce));
882         }
883     }
884     /**
885      * Convert a String value to a Document
886      * @param value The current value (can be null)
887      * @return the value as a DOM Element or <code>null</code>
888      * @throws IllegalArgumentException if the value could not be converted
889      */

890     static private Document convertStringToXML(String JavaDoc value) {
891         if (value == null) {
892             return null;
893         }
894         if (log.isDebugEnabled()) {
895             log.trace("using xml string:\n" + value);
896         }
897         try {
898             Document doc;
899             final XMLErrorHandler errorHandler = new XMLErrorHandler(false, org.mmbase.util.XMLErrorHandler.NEVER);
900             synchronized(DOCUMENTBUILDER) {
901                 // dont log errors, and try to process as much as possible...
902
DOCUMENTBUILDER.setErrorHandler(errorHandler);
903                 // ByteArrayInputStream?
904
// Yes, in contradiction to what one would think, XML are bytes, rather then characters.
905
doc = DOCUMENTBUILDER.parse(new java.io.ByteArrayInputStream JavaDoc(value.getBytes("UTF-8")));
906             }
907             if (log.isDebugEnabled()) {
908                 log.trace("parsed: " + XMLWriter.write(doc, false, true));
909             }
910             if (!errorHandler.foundNothing()) {
911                 throw new IllegalArgumentException JavaDoc("xml invalid:\n" + errorHandler.getMessageBuffer() + "for xml:\n" + value);
912             }
913             return doc;
914         } catch (org.xml.sax.SAXException JavaDoc se) {
915             log.debug("[sax] not well formed xml: " + se.toString() + "(" + se.getMessage() + ")\n" + Logging.stackTrace(se));
916             return convertStringToXML("<p>" + Encode.encode("ESCAPE_XML", value) + "</p>"); // Should _always_ be sax-compliant.
917
} catch (java.io.IOException JavaDoc ioe) {
918             String JavaDoc msg = "[io] not well formed xml: " + ioe.toString() + "\n" + Logging.stackTrace(ioe);
919             log.error(msg);
920             throw new IllegalArgumentException JavaDoc(msg);
921         }
922     }
923
924
925     /*
926      * Wraps a List with an 'Escaper'.
927      * @since MMBase-1.8
928      */

929     public static class ListWrapper extends AbstractList{
930         private final List list;
931         private final CharTransformer escaper;
932         ListWrapper (List l, CharTransformer e) {
933             list = l;
934             escaper = e;
935         }
936         public Object JavaDoc get(int index) { return Casting.wrap(list.get(index), escaper); }
937         public int size() { return list.size(); }
938         public Object JavaDoc set(int index, Object JavaDoc value) { return list.set(index, value); }
939         public void add(int index, Object JavaDoc value) { list.add(index, value); }
940         public Object JavaDoc remove(int index) { return list.remove(index); }
941         public boolean isEmpty() {return list.isEmpty();}
942         public boolean contains(Object JavaDoc o) {return list.contains(o);}
943         public Object JavaDoc[] toArray() {return list.toArray();}
944         public Object JavaDoc[] toArray(Object JavaDoc[] a) {return list.toArray(a);}
945         public Iterator iterator() { return list.iterator(); }
946         public ListIterator listIterator() { return list.listIterator(); }
947         public String JavaDoc toString() {
948             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
949             Iterator i = list.iterator();
950             boolean hasNext = i.hasNext();
951             while (hasNext) {
952                 Casting.toStringBuffer(buf, i.next());
953                 hasNext = i.hasNext();
954                 if (hasNext) {
955                     buf.append(',');
956                 }
957             }
958             return buf.toString();
959         }
960         public List getList() {
961             return list;
962         }
963     }
964
965     /**
966      * Wraps a String with an 'Escaper'.
967      * @since MMBase-1.8
968      */

969     public static class StringWrapper implements CharSequence JavaDoc {
970         private final CharTransformer escaper;
971         private final CharSequence JavaDoc string;
972         private String JavaDoc escaped = null;
973         StringWrapper(CharSequence JavaDoc s, CharTransformer e) {
974             escaper = e;
975             string = s;
976
977         }
978
979         public char charAt(int index) {
980             toString();
981             return escaped.charAt(index);
982         }
983         public int length() {
984             toString();
985             return escaped.length();
986         }
987
988         public CharSequence JavaDoc subSequence(int start, int end) {
989             toString();
990             return escaped.subSequence(start, end);
991         }
992
993         public String JavaDoc toString() {
994             if (escaped == null) escaped = escape(escaper, string);
995             return escaped;
996         }
997         public CharSequence JavaDoc getString() {
998             return string;
999         }
1000    }
1001
1002}
1003
1004
1005
Popular Tags