KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > service > cmr > repository > datatype > TypeConverter


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.service.cmr.repository.datatype;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
25 import org.alfresco.service.cmr.dictionary.DictionaryException;
26 import org.alfresco.util.ParameterCheck;
27
28
29 /**
30  * Support for generic conversion between types.
31  *
32  * Additional conversions may be added.
33  *
34  * Direct conversion and two stage conversions via Number are supported. We do
35  * not support conversion by any route at the moment
36  */

37 public class TypeConverter
38 {
39
40     /**
41      * General conversion method to Object types (note it cannot support
42      * conversion to primary types due the restrictions of reflection. Use the
43      * static conversion methods to primitive types)
44      *
45      * @param propertyType - the target property type
46      * @param value - the value to be converted
47      * @return - the converted value as the correct type
48      */

49     @SuppressWarnings JavaDoc("unchecked")
50     public final Object JavaDoc convert(DataTypeDefinition propertyType, Object JavaDoc value)
51     {
52         ParameterCheck.mandatory("Property type definition", propertyType);
53         
54         // Convert property type to java class
55
Class JavaDoc javaClass = null;
56         String JavaDoc javaClassName = propertyType.getJavaClassName();
57         try
58         {
59             javaClass = Class.forName(javaClassName);
60         }
61         catch (ClassNotFoundException JavaDoc e)
62         {
63             throw new DictionaryException("Java class " + javaClassName + " of property type " + propertyType.getName() + " is invalid", e);
64         }
65         
66         return convert(javaClass, value);
67     }
68
69     /**
70      * General conversion method to Object types (note it cannot support
71      * conversion to primary types due the restrictions of reflection. Use the
72      * static conversion methods to primitive types)
73      *
74      * @param <T> The target type for the result of the conversion
75      * @param c - a class for the target type
76      * @param value - the value to be converted
77      * @return - the converted value as the correct type
78      * @throws TypeConversionException if the conversion cannot be performed
79      */

80     @SuppressWarnings JavaDoc("unchecked")
81     public final <T> T convert(Class JavaDoc<T> c, Object JavaDoc value)
82     {
83         if(value == null)
84         {
85             return null;
86         }
87
88         // Primative types
89
if (c.isPrimitive())
90         {
91             // We can not suport primitive type conversion
92
throw new TypeConversionException("Can not convert direct to primitive type " + c.getName());
93         }
94
95         // Check if we already have the correct type
96
if (c.isInstance(value))
97         {
98             return c.cast(value);
99         }
100
101         // Find the correct conversion - if available and do the converiosn
102
Converter converter = getConverter(value, c);
103         if (converter == null)
104         {
105             throw new TypeConversionException(
106                     "There is no conversion registered for the value: \n" +
107                     " value class: " + value.getClass().getName() + "\n" +
108                     " to class: " + c.getName() + "\n" +
109                     " value: " + value.toString());
110         }
111         
112         return (T) converter.convert(value);
113     }
114
115     /**
116      * General conversion method to convert collection contents to the specified
117      * type.
118      *
119      * @param propertyType - the target property type
120      * @param value - the value to be converted
121      * @return - the converted value as the correct type
122      * @throws DictionaryException if the property type's registered java class is invalid
123      * @throws TypeConversionException if the conversion cannot be performed
124      */

125     @SuppressWarnings JavaDoc("unchecked")
126     public final Collection JavaDoc convert(DataTypeDefinition propertyType, Collection JavaDoc values)
127     {
128         ParameterCheck.mandatory("Property type definition", propertyType);
129         
130         // Convert property type to java class
131
Class JavaDoc javaClass = null;
132         String JavaDoc javaClassName = propertyType.getJavaClassName();
133         try
134         {
135             javaClass = Class.forName(javaClassName);
136         }
137         catch (ClassNotFoundException JavaDoc e)
138         {
139             throw new DictionaryException("Java class " + javaClassName + " of property type " + propertyType.getName() + " is invalid", e);
140         }
141         
142         return convert(javaClass, values);
143     }
144     
145     /**
146      * General conversion method to convert collection contents to the specified
147      * type.
148      *
149      * @param <T> The target type for the result of the conversion
150      * @param c - a class for the target type
151      * @param value - the collection to be converted
152      * @return - the converted collection
153      * @throws TypeConversionException if the conversion cannot be performed
154      */

155     public final <T> Collection JavaDoc<T> convert(Class JavaDoc<T> c, Collection JavaDoc values)
156     {
157         if(values == null)
158         {
159             return null;
160         }
161
162         Collection JavaDoc<T> converted = new ArrayList JavaDoc<T>(values.size());
163         for (Object JavaDoc value : values)
164         {
165             converted.add(convert(c, value));
166         }
167
168         return converted;
169     }
170     
171     /**
172      * Get the boolean value for the value object
173      * May have conversion failure
174      *
175      * @param value
176      * @return
177      */

178     public final boolean booleanValue(Object JavaDoc value)
179     {
180         return convert(Boolean JavaDoc.class, value).booleanValue();
181     }
182     
183     /**
184      * Get the char value for the value object
185      * May have conversion failure
186      *
187      * @param value
188      * @return
189      */

190     public final char charValue(Object JavaDoc value)
191     {
192         return convert(Character JavaDoc.class, value).charValue();
193     }
194     
195     /**
196      * Get the byte value for the value object
197      * May have conversion failure
198      *
199      * @param value
200      * @return
201      */

202     public final byte byteValue(Object JavaDoc value)
203     {
204         if (value instanceof Number JavaDoc)
205         {
206             return ((Number JavaDoc) value).byteValue();
207         }
208         return convert(Byte JavaDoc.class, value).byteValue();
209     }
210
211     /**
212      * Get the short value for the value object
213      * May have conversion failure
214      *
215      * @param value
216      * @return
217      */

218     public final short shortValue(Object JavaDoc value)
219     {
220         if (value instanceof Number JavaDoc)
221         {
222             return ((Number JavaDoc) value).shortValue();
223         }
224         return convert(Short JavaDoc.class, value).shortValue();
225     }
226     
227     /**
228      * Get the int value for the value object
229      * May have conversion failure
230      *
231      * @param value
232      * @return
233      */

234     public final int intValue(Object JavaDoc value)
235     {
236         if (value instanceof Number JavaDoc)
237         {
238             return ((Number JavaDoc) value).intValue();
239         }
240         return convert(Integer JavaDoc.class, value).intValue();
241     }
242     
243     /**
244      * Get the long value for the value object
245      * May have conversion failure
246      *
247      * @param value
248      * @return
249      */

250     public final long longValue(Object JavaDoc value)
251     {
252         if (value instanceof Number JavaDoc)
253         {
254             return ((Number JavaDoc) value).longValue();
255         }
256         return convert(Long JavaDoc.class, value).longValue();
257     }
258
259     /**
260      * Get the bollean value for the value object
261      * May have conversion failure
262      *
263      * @param float
264      * @return
265      */

266     public final float floatValue(Object JavaDoc value)
267     {
268         if (value instanceof Number JavaDoc)
269         {
270             return ((Number JavaDoc) value).floatValue();
271         }
272         return convert(Float JavaDoc.class, value).floatValue();
273     }
274     
275     /**
276      * Get the bollean value for the value object
277      * May have conversion failure
278      *
279      * @param double
280      * @return
281      */

282     public final double doubleValue(Object JavaDoc value)
283     {
284         if (value instanceof Number JavaDoc)
285         {
286             return ((Number JavaDoc) value).doubleValue();
287         }
288         return convert(Double JavaDoc.class, value).doubleValue();
289     }
290
291     /**
292      * Is the value multi valued
293      *
294      * @param value
295      * @return true - if the underlyinf is a collection of values and not a singole value
296      */

297     public final boolean isMultiValued(Object JavaDoc value)
298     {
299         return (value instanceof Collection JavaDoc);
300     }
301
302     /**
303      * Get the number of values represented
304      *
305      * @param value
306      * @return 1 for normal values and the size of the collection for MVPs
307      */

308     public final int size(Object JavaDoc value)
309     {
310         if (value instanceof Collection JavaDoc)
311         {
312             return ((Collection JavaDoc) value).size();
313         }
314         else
315         {
316             return 1;
317         }
318     }
319
320     /**
321      * Get a collection for the passed value
322      *
323      * @param value
324      * @return
325      */

326     private final Collection JavaDoc createCollection(Object JavaDoc value)
327     {
328         Collection JavaDoc coll;
329         if (isMultiValued(value))
330         {
331             coll = (Collection JavaDoc) value;
332         }
333         else
334         {
335             ArrayList JavaDoc<Object JavaDoc> list = new ArrayList JavaDoc<Object JavaDoc>(1);
336             list.add(value);
337             coll = list;
338         }
339         return coll;
340     }
341
342     /**
343      * Get a collection for the passed value converted to the specified type
344      *
345      * @param c
346      * @param value
347      * @return
348      */

349     public final <T> Collection JavaDoc<T> getCollection(Class JavaDoc<T> c, Object JavaDoc value)
350     {
351         Collection JavaDoc coll = createCollection(value);
352         return convert(c, coll);
353     }
354         
355     /**
356      * Add a converter to the list of those available
357      *
358      * @param <F>
359      * @param <T>
360      * @param source
361      * @param destination
362      * @param converter
363      */

364     public final <F, T> void addConverter(Class JavaDoc<F> source, Class JavaDoc<T> destination, Converter<F, T> converter)
365     {
366         Map JavaDoc<Class JavaDoc, Converter> map = conversions.get(source);
367         if (map == null)
368         {
369             map = new HashMap JavaDoc<Class JavaDoc, Converter>();
370             conversions.put(source, map);
371         }
372         map.put(destination, converter);
373     }
374
375     /**
376      * Add a dynamic two stage converter
377      * @param <F> from
378      * @param <I> intermediate
379      * @param <T> to
380      * @param source
381      * @param intermediate
382      * @param destination
383      */

384     public final <F, I, T> Converter<F, T> addDynamicTwoStageConverter(Class JavaDoc<F> source, Class JavaDoc<I> intermediate, Class JavaDoc<T> destination)
385     {
386         Converter<F, T> converter = new TypeConverter.DynamicTwoStageConverter<F, I, T>(source, intermediate, destination);
387         addConverter(source, destination, converter);
388         return converter;
389     }
390
391     /**
392      * Find conversion for the specified object
393      *
394      * Note: Takes into account the class of the object and any interfaces it may
395      * also support.
396      *
397      * @param <F>
398      * @param <T>
399      * @param source
400      * @param dest
401      * @return
402      */

403     @SuppressWarnings JavaDoc("unchecked")
404     public final <T> Converter getConverter(Object JavaDoc value, Class JavaDoc<T> dest)
405     {
406         Converter converter = null;
407         if (value == null)
408         {
409             return null;
410         }
411
412         // find via class of value
413
Class JavaDoc valueClass = value.getClass();
414         converter = getConverter(valueClass, dest);
415         if (converter != null)
416         {
417             return converter;
418         }
419         
420         // find via supported interfaces of value
421
do
422         {
423             Class JavaDoc[] ifClasses = valueClass.getInterfaces();
424             for (Class JavaDoc ifClass : ifClasses)
425             {
426                 converter = getConverter(ifClass, dest);
427                 if (converter != null)
428                 {
429                     return converter;
430                 }
431             }
432             valueClass = valueClass.getSuperclass();
433         }
434         while (valueClass != null);
435         
436         return null;
437     }
438
439     /**
440      * Find a conversion for a specific Class
441      *
442      * @param <F>
443      * @param <T>
444      * @param source
445      * @param dest
446      * @return
447      */

448     public <F, T> Converter getConverter(Class JavaDoc<F> source, Class JavaDoc<T> dest)
449     {
450         Converter<?, ?> converter = null;
451         Class JavaDoc clazz = source;
452         do
453         {
454             Map JavaDoc<Class JavaDoc, Converter> map = conversions.get(clazz);
455             if (map == null)
456             {
457                 continue;
458             }
459             converter = map.get(dest);
460             
461             if (converter == null)
462             {
463                 // attempt to establish converter from source to dest via Number
464
Converter<?, ?> first = map.get(Number JavaDoc.class);
465                 Converter<?, ?> second = null;
466                 if (first != null)
467                 {
468                     map = conversions.get(Number JavaDoc.class);
469                     if (map != null)
470                     {
471                         second = map.get(dest);
472                     }
473                 }
474                 if (second != null)
475                 {
476                     converter = new TwoStageConverter<F, Number JavaDoc, T>(first, second);
477                 }
478             }
479         }
480         while ((converter == null) && ((clazz = clazz.getSuperclass()) != null));
481
482         return converter;
483     }
484
485     /**
486      * Map of conversion
487      */

488     private Map JavaDoc<Class JavaDoc, Map JavaDoc<Class JavaDoc, Converter>> conversions = new HashMap JavaDoc<Class JavaDoc, Map JavaDoc<Class JavaDoc, Converter>>();
489
490
491     // Support for pluggable conversions
492

493     /**
494      * Conversion interface
495      *
496      * @author andyh
497      *
498      * @param <F> From type
499      * @param <T> To type
500      */

501     public interface Converter<F, T>
502     {
503         public T convert(F source);
504     }
505
506     /**
507      * Support for chaining conversions
508      *
509      * @author andyh
510      *
511      * @param <F> From Type
512      * @param <I> Intermediate type
513      * @param <T> To Type
514      */

515     public static class TwoStageConverter<F, I, T> implements Converter<F, T>
516     {
517         Converter first;
518
519         Converter second;
520
521         TwoStageConverter(Converter first, Converter second)
522         {
523             this.first = first;
524             this.second = second;
525         }
526
527         @SuppressWarnings JavaDoc("unchecked")
528         public T convert(F source)
529         {
530             return (T) second.convert((I) first.convert(source));
531         }
532     }
533     
534     /**
535      * Support for chaining conversions
536      *
537      * @author David Caruana
538      *
539      * @param <F> From Type
540      * @param <I> Intermediate type
541      * @param <T> To Type
542      */

543     protected class DynamicTwoStageConverter<F, I, T> implements Converter<F, T>
544     {
545         Class JavaDoc<F> from;
546         Class JavaDoc<I> intermediate;
547         Class JavaDoc<T> to;
548         
549         DynamicTwoStageConverter(Class JavaDoc<F> from, Class JavaDoc<I> intermediate, Class JavaDoc<T> to)
550         {
551             this.from = from;
552             this.intermediate = intermediate;
553             this.to = to;
554         }
555         
556         /**
557          * @return from class
558          */

559         public Class JavaDoc<F> getFrom()
560         {
561             return from;
562         }
563         
564         /**
565          * @return intermediate class
566          */

567         public Class JavaDoc<I> getIntermediate()
568         {
569             return intermediate;
570         }
571         
572         /**
573          * @return to class
574          */

575         public Class JavaDoc<T> getTo()
576         {
577             return to;
578         }
579         
580         @SuppressWarnings JavaDoc("unchecked")
581         public T convert(F source)
582         {
583             Converter iConverter = TypeConverter.this.getConverter(from, intermediate);
584             Converter tConverter = TypeConverter.this.getConverter(intermediate, to);
585             if (iConverter == null || tConverter == null)
586             {
587                 throw new TypeConversionException("Cannot convert from " + from.getName() + " to " + to.getName());
588             }
589             
590             Object JavaDoc iValue = iConverter.convert(source);
591             Object JavaDoc tValue = tConverter.convert(iValue);
592             return (T)tValue;
593         }
594     }
595     
596 }
597
Popular Tags