1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.seasar.cubby.converter.impl;
17
18 import java.lang.reflect.Modifier;
19 import java.util.HashMap;
20 import java.util.LinkedHashSet;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.TreeMap;
24
25 import org.seasar.cubby.controller.ClassDetector;
26 import org.seasar.cubby.controller.DetectClassProcessor;
27 import org.seasar.cubby.converter.Converter;
28 import org.seasar.cubby.converter.ConverterFactory;
29 import org.seasar.framework.container.S2Container;
30 import org.seasar.framework.convention.NamingConvention;
31 import org.seasar.framework.util.ClassUtil;
32 import org.seasar.framework.util.Disposable;
33 import org.seasar.framework.util.DisposableUtil;
34
35
36
37
38
39
40
41 public class ConverterFactoryImpl implements ConverterFactory, DetectClassProcessor,
42 Disposable {
43
44
45 private boolean initialized;
46
47
48 private S2Container container;
49
50
51 private NamingConvention namingConvention;
52
53
54 private ClassDetector classDetector;
55
56
57 private Set<Converter> converters = new LinkedHashSet<Converter>();
58
59
60 private Map<String, Converter> converterCache = new HashMap<String, Converter>();
61
62
63
64
65 public ConverterFactoryImpl() {
66 }
67
68
69
70
71
72
73
74 public void setContainer(final S2Container container) {
75 this.container = container.getRoot();
76 }
77
78
79
80
81
82
83
84 public void setNamingConvention(final NamingConvention namingConvention) {
85 this.namingConvention = namingConvention;
86 }
87
88
89
90
91
92
93
94 public void setClassDetector(final ClassDetector classDetector) {
95 this.classDetector = classDetector;
96 }
97
98
99
100
101 public void initialize() {
102 if (initialized) {
103 return;
104 }
105 classDetector.detect();
106
107 for (final Converter converter : Converter[].class.cast(container
108 .findAllComponents(Converter.class))) {
109 converters.add(converter);
110 }
111 DisposableUtil.add(this);
112 initialized = true;
113 }
114
115
116
117
118
119 public void dispose() {
120 converters.clear();
121 converterCache.clear();
122 initialized = false;
123 }
124
125
126
127
128 public Converter getConverter(final Class<?> parameterType,
129 final Class<?> objectType) {
130 initialize();
131 final Class<?> destType = ClassUtil
132 .getWrapperClassIfPrimitive(objectType);
133 final String cacheKey = cacheKey(parameterType, destType);
134 final Converter converter = converterCache.get(cacheKey);
135 if (converter != null) {
136 return converter;
137 }
138 return detectConverter(parameterType, destType);
139 }
140
141 private Converter detectConverter(final Class<?> parameterType,
142 final Class<?> objectType) {
143 final Converter converter = getDistanceTable(parameterType, objectType);
144 final String cacheKey = cacheKey(parameterType, objectType);
145 converterCache.put(cacheKey, converter);
146 return converter;
147 }
148
149 private static String cacheKey(final Class<?> parameterType,
150 final Class<?> objectType) {
151 if (parameterType == null) {
152 return objectType.getName();
153 }
154 return parameterType.getName() + objectType.getName();
155 }
156
157 private Converter getDistanceTable(final Class<?> parameterType,
158 final Class<?> objectType) {
159 final Map<Integer, Converter> distanceTable = new TreeMap<Integer, Converter>();
160 for (final Converter converter : converters) {
161 if (!converter.canConvert(parameterType, objectType)) {
162 continue;
163 }
164 final int distance = getDistance(converter.getObjectType(),
165 objectType);
166 distanceTable.put(distance, converter);
167 }
168 if (distanceTable.isEmpty()) {
169 return null;
170 }
171 return distanceTable.values().iterator().next();
172 }
173
174 private int getDistance(final Class<?> assigner, final Class<?> assignee) {
175 return getDistance(assigner, assignee, 0);
176 }
177
178 private int getDistance(final Class<?> assigner, final Class<?> assignee,
179 final int distance) {
180 if (assignee.equals(assigner)) {
181 return distance;
182 }
183 if (Enum.class.equals(assigner) && assignee.isEnum()) {
184 return distance + 5;
185 }
186 if (isImplements(assigner, assignee)) {
187 return distance + 5;
188 }
189
190 final Class<?> superClass = assigner.getSuperclass();
191 if (superClass == null) {
192 return distance + 10;
193 }
194 return getDistance(superClass, assignee, distance + 10);
195 }
196
197 private boolean isImplements(final Class<?> assigner,
198 final Class<?> assignee) {
199 return !assigner.isInterface() && assignee.isInterface()
200 && assignee.isAssignableFrom(assigner);
201 }
202
203
204
205
206
207
208
209 public void processClass(final String packageName,
210 final String shortClassName) {
211 if (shortClassName.indexOf('$') != -1) {
212 return;
213 }
214 final String className = ClassUtil.concatName(packageName,
215 shortClassName);
216 if (!namingConvention.isTargetClassName(className)) {
217 return;
218 }
219 if (!className.endsWith(namingConvention.getConverterSuffix())) {
220 return;
221 }
222 final Class<?> clazz = ClassUtil.forName(className);
223 if (namingConvention.isSkipClass(clazz)) {
224 return;
225 }
226 if ((clazz.getModifiers() & Modifier.ABSTRACT) != 0) {
227 return;
228 }
229 if (!Converter.class.isAssignableFrom(clazz)) {
230 return;
231 }
232 final Converter converter = Converter.class.cast(container
233 .getComponent(clazz));
234 converters.add(converter);
235 }
236
237 }