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.util.HashMap;
19 import java.util.Map;
20 import java.util.TreeMap;
21
22 import org.seasar.cubby.converter.Converter;
23 import org.seasar.cubby.converter.ConverterFactory;
24 import org.seasar.framework.container.S2Container;
25 import org.seasar.framework.util.ClassUtil;
26 import org.seasar.framework.util.Disposable;
27 import org.seasar.framework.util.DisposableUtil;
28
29
30
31
32
33
34
35 public class ConverterFactoryImpl implements ConverterFactory, Disposable {
36
37
38 protected boolean initialized;
39
40
41 protected S2Container container;
42
43
44 protected Converter[] converters;
45
46
47 protected Map<String, Converter> converterCache = new HashMap<String, Converter>();
48
49
50
51
52
53 public ConverterFactoryImpl() {
54 }
55
56
57
58
59
60
61
62 public void setContainer(final S2Container container) {
63 this.container = container.getRoot();
64 }
65
66
67
68
69 public void initialize() {
70 if (initialized) {
71 return;
72 }
73 converters = (Converter[]) container.findAllComponents(Converter.class);
74 DisposableUtil.add(this);
75 initialized = true;
76 }
77
78
79
80
81
82 public void dispose() {
83 converters = null;
84 converterCache.clear();
85 initialized = false;
86 }
87
88
89
90
91 public Converter getConverter(final Class<?> parameterType,
92 final Class<?> objectType) {
93 initialize();
94 final Class<?> destType = ClassUtil
95 .getWrapperClassIfPrimitive(objectType);
96 final String cacheKey = cacheKey(parameterType, destType);
97 final Converter converter = converterCache.get(cacheKey);
98 if (converter != null) {
99 return converter;
100 }
101 return detectConverter(parameterType, destType);
102 }
103
104 private Converter detectConverter(final Class<?> parameterType,
105 final Class<?> objectType) {
106 final Converter converter = getDistanceTable(parameterType, objectType);
107 final String cacheKey = cacheKey(parameterType, objectType);
108 converterCache.put(cacheKey, converter);
109 return converter;
110 }
111
112 private static String cacheKey(final Class<?> parameterType,
113 final Class<?> objectType) {
114 if (parameterType == null) {
115 return objectType.getName();
116 }
117 return parameterType.getName() + objectType.getName();
118 }
119
120 private Converter getDistanceTable(final Class<?> parameterType,
121 final Class<?> objectType) {
122 final Map<Integer, Converter> distanceTable = new TreeMap<Integer, Converter>();
123 for (final Converter converter : converters) {
124 if (!converter.canConvert(parameterType, objectType)) {
125 continue;
126 }
127 final int distance = getDistance(converter.getObjectType(),
128 objectType);
129 distanceTable.put(distance, converter);
130 }
131 if (distanceTable.isEmpty()) {
132 return null;
133 }
134 return distanceTable.values().iterator().next();
135 }
136
137 private int getDistance(final Class<?> assigner, final Class<?> assignee) {
138 return getDistance(assigner, assignee, 0);
139 }
140
141 private int getDistance(final Class<?> assigner, final Class<?> assignee,
142 final int distance) {
143 if (assignee.equals(assigner)) {
144 return distance;
145 }
146 if (Enum.class.equals(assigner) && assignee.isEnum()) {
147 return distance + 5;
148 }
149 if (isImplements(assigner, assignee)) {
150 return distance + 5;
151 }
152
153 final Class<?> superClass = assigner.getSuperclass();
154 if (superClass == null) {
155 return distance + 10;
156 }
157 return getDistance(superClass, assignee, distance + 10);
158 }
159
160 private boolean isImplements(final Class<?> assigner,
161 final Class<?> assignee) {
162 return !assigner.isInterface() && assignee.isInterface()
163 && assignee.isAssignableFrom(assigner);
164 }
165
166 }