KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > binding > convert > support > GenericConversionService


1 /*
2  * Copyright 2002-2006 the original author or authors.
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 org.springframework.binding.convert.support;
17
18 import java.util.Arrays JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.LinkedList JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.springframework.binding.convert.ConversionExecutor;
28 import org.springframework.binding.convert.ConversionService;
29 import org.springframework.binding.convert.Converter;
30 import org.springframework.util.Assert;
31 import org.springframework.util.ClassUtils;
32 import org.springframework.util.StringUtils;
33
34 /**
35  * Base implementation of a conversion service.
36  *
37  * @author Keith Donald
38  */

39 public class GenericConversionService implements ConversionService {
40
41     /**
42      * An indexed map of converters. Each entry key is a source class that can
43      * be converted from, and each entry value is a map of target classes that
44      * can be convertered to, ultimately mapping to a specific converter that
45      * can perform the source->target conversion.
46      */

47     private Map JavaDoc sourceClassConverters = new HashMap JavaDoc();
48
49     /**
50      * A map of string aliases to convertible classes. Allows lookup of
51      * converters by alias.
52      */

53     private Map JavaDoc aliasMap = new HashMap JavaDoc();
54
55     /**
56      * An optional parent conversion service.
57      */

58     private ConversionService parent;
59
60     public void setParent(ConversionService parent) {
61         this.parent = parent;
62     }
63
64     public void addConverter(Converter converter) {
65         Class JavaDoc[] sourceClasses = converter.getSourceClasses();
66         Class JavaDoc[] targetClasses = converter.getTargetClasses();
67         for (int i = 0; i < sourceClasses.length; i++) {
68             Class JavaDoc sourceClass = sourceClasses[i];
69             Map JavaDoc sourceMap = (Map JavaDoc)sourceClassConverters.get(sourceClass);
70             if (sourceMap == null) {
71                 sourceMap = new HashMap JavaDoc();
72                 sourceClassConverters.put(sourceClass, sourceMap);
73             }
74             for (int j = 0; j < targetClasses.length; j++) {
75                 Class JavaDoc targetClass = targetClasses[j];
76                 sourceMap.put(targetClass, converter);
77             }
78         }
79         if (converter instanceof ConversionServiceAware) {
80             ((ConversionServiceAware)converter).setConversionService(this);
81         }
82     }
83
84     public void addConverter(Converter converter, String JavaDoc alias) {
85         aliasMap.put(alias, converter);
86         addConverter(converter);
87     }
88
89     public void addConverters(Converter[] converters) {
90         for (int i = 0; i < converters.length; i++) {
91             addConverter(converters[i]);
92         }
93     }
94
95     public void addAlias(String JavaDoc alias, Class JavaDoc targetType) {
96         aliasMap.put(alias, targetType);
97     }
98
99     public void addDefaultAlias(Class JavaDoc targetType) {
100         addAlias(StringUtils.uncapitalize(ClassUtils.getShortName(targetType)), targetType);
101     }
102
103     public ConversionExecutor[] getConversionExecutorsForSource(Class JavaDoc sourceClass) {
104         Assert.notNull(sourceClass, "The source class to convert from is required");
105         Map JavaDoc sourceTargetConverters = findConvertersForSource(sourceClass);
106         if (sourceTargetConverters.isEmpty()) {
107             if (parent != null) {
108                 return parent.getConversionExecutorsForSource(sourceClass);
109             }
110             else {
111                 return new ConversionExecutor[0];
112             }
113         }
114         Set JavaDoc executors = new HashSet JavaDoc();
115         if (parent != null) {
116             executors.addAll(Arrays.asList(parent.getConversionExecutorsForSource(sourceClass)));
117         }
118         Iterator JavaDoc it = sourceTargetConverters.entrySet().iterator();
119         while (it.hasNext()) {
120             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)it.next();
121             executors.add(new ConversionExecutor(sourceClass, (Class JavaDoc)entry.getKey(), (Converter)entry.getValue()));
122         }
123         return (ConversionExecutor[])executors.toArray(new ConversionExecutor[executors.size()]);
124     }
125
126     public ConversionExecutor getConversionExecutor(Class JavaDoc sourceClass, Class JavaDoc targetClass) {
127         Assert.notNull(sourceClass, "The source class to convert from is required");
128         Assert.notNull(targetClass, "The target class to convert to is required");
129         if (this.sourceClassConverters == null || this.sourceClassConverters.isEmpty()) {
130             throw new IllegalStateException JavaDoc("No converters have been added to this service's registry");
131         }
132         if (sourceClass.equals(targetClass)) {
133             return new ConversionExecutor(sourceClass, targetClass, new NoOpConverter(sourceClass, targetClass));
134         }
135         Map JavaDoc sourceTargetConverters = findConvertersForSource(sourceClass);
136         Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
137         if (converter != null) {
138             return new ConversionExecutor(sourceClass, targetClass, converter);
139         }
140         else {
141             if (parent != null) {
142                 return parent.getConversionExecutor(sourceClass, targetClass);
143             }
144             else {
145                 throw new IllegalArgumentException JavaDoc("No converter registered to convert from sourceClass '"
146                         + sourceClass + "' to target class '" + targetClass + "'");
147             }
148         }
149     }
150
151     public ConversionExecutor getConversionExecutorByTargetAlias(Class JavaDoc sourceClass, String JavaDoc alias)
152             throws IllegalArgumentException JavaDoc {
153         Assert.notNull(sourceClass, "The source class to convert from is required");
154         Assert.hasText(alias, "The target alias is required and must either be a type alias (e.g 'boolean') "
155                 + "or a generic converter alias (e.g. 'bean') ");
156         Object JavaDoc targetType = aliasMap.get(alias);
157         if (targetType == null) {
158             if (parent != null) {
159                 return parent.getConversionExecutorByTargetAlias(sourceClass, alias);
160             }
161             else {
162                 return null;
163             }
164         }
165         else if (targetType instanceof Class JavaDoc) {
166             return getConversionExecutor(sourceClass, (Class JavaDoc)targetType);
167         }
168         else {
169             Assert.isInstanceOf(Converter.class, targetType, "Not a converter: ");
170             Converter conv = (Converter)targetType;
171             return new ConversionExecutor(sourceClass, Object JavaDoc.class, conv);
172         }
173     }
174
175     public Class JavaDoc getClassByAlias(String JavaDoc alias) {
176         Assert.hasText(alias, "The alias is required and must be a type alias (e.g 'boolean')");
177         Object JavaDoc clazz = aliasMap.get(alias);
178         if (clazz != null) {
179             Assert.isInstanceOf(Class JavaDoc.class, clazz, "Not a Class alias '" + alias + "': ");
180             return (Class JavaDoc)clazz;
181         } else {
182             if (parent != null) {
183                 // try parent service
184
return parent.getClassByAlias(alias);
185             } else {
186                 // alias does not index a class, return null
187
return null;
188             }
189         }
190     }
191
192     protected Map JavaDoc findConvertersForSource(Class JavaDoc sourceClass) {
193         LinkedList JavaDoc classQueue = new LinkedList JavaDoc();
194         classQueue.addFirst(sourceClass);
195         while (!classQueue.isEmpty()) {
196             sourceClass = (Class JavaDoc)classQueue.removeLast();
197             Map JavaDoc sourceTargetConverters = (Map JavaDoc)sourceClassConverters.get(sourceClass);
198             if (sourceTargetConverters != null && !sourceTargetConverters.isEmpty()) {
199                 return sourceTargetConverters;
200             }
201             if (!sourceClass.isInterface() && (sourceClass.getSuperclass() != null)) {
202                 classQueue.addFirst(sourceClass.getSuperclass());
203             }
204             // queue up source class's implemented interfaces.
205
Class JavaDoc[] interfaces = sourceClass.getInterfaces();
206             for (int i = 0; i < interfaces.length; i++) {
207                 classQueue.addFirst(interfaces[i]);
208             }
209         }
210         return Collections.EMPTY_MAP;
211     }
212
213     private Converter findTargetConverter(Map JavaDoc sourceTargetConverters, Class JavaDoc targetClass) {
214         LinkedList JavaDoc classQueue = new LinkedList JavaDoc();
215         classQueue.addFirst(targetClass);
216         while (!classQueue.isEmpty()) {
217             targetClass = (Class JavaDoc)classQueue.removeLast();
218             Converter converter = (Converter)sourceTargetConverters.get(targetClass);
219             if (converter != null) {
220                 return converter;
221             }
222             if (!targetClass.isInterface() && (targetClass.getSuperclass() != null)) {
223                 classQueue.addFirst(targetClass.getSuperclass());
224             }
225             // queue up target class's implemented interfaces.
226
Class JavaDoc[] interfaces = targetClass.getInterfaces();
227             for (int i = 0; i < interfaces.length; i++) {
228                 classQueue.addFirst(interfaces[i]);
229             }
230         }
231         return null;
232     }
233
234     public ConversionService getParent() {
235         return parent;
236     }
237
238     protected Map JavaDoc getSourceClassConverters() {
239         return sourceClassConverters;
240     }
241
242     protected Map JavaDoc getAliasMap() {
243         return aliasMap;
244     }
245 }
Popular Tags