DecoratingService.java

biz/hammurapi/convert/DecoratingService.java

Violations

Inspector Message Severity Location
Java Inspector 048 Copyrights information should be present in each file. 1
Java Inspector 015 Do not change parameter value. For comprehensibility, formal parameters should be final 2 99:25
Java Inspector 015 Do not change parameter value. For comprehensibility, formal parameters should be final 2 103:25
Java Inspector 049 Use a Collection instead of arrays Object[] 2 89:22
Java Inspector 049 Use a Collection instead of arrays Object[] 2 125:22
Java Inspector 049 Use a Collection instead of arrays Object[] 2 204:39
Java Inspector 049 Use a Collection instead of arrays Object[] 2 208:49
Java Inspector 049 Use a Collection instead of arrays Object[] 2 296:54
Java Inspector 070-A Cyclomatic complexity is too high: 17, maximum allowed is 12 2 192:17
Java Inspector 081 Avoid static collections, they can grow in size over time. 2 316:9
Java Inspector 089 Undocumented method 2 28:17
Java Inspector 089 Undocumented method 2 128:25
Java Inspector 089 Undocumented method 2 132:25
Java Inspector 089 Undocumented method 2 180:25
Java Inspector 089 Undocumented method 2 212:65
Java Inspector 089 Undocumented method 2 222:65
Java Inspector 089 Undocumented method 2 230:65
Java Inspector 089 Undocumented method 2 240:65
Java Inspector 089 Undocumented method 2 248:65
Java Inspector 089 Undocumented method 2 258:65
Java Inspector 089 Undocumented method 2 266:65
Java Inspector 089 Undocumented method 2 276:65
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 227:77
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 245:77
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 263:77

Source code

1package biz.hammurapi.convert;
2
3import java.lang.reflect.InvocationTargetException;
4import java.lang.reflect.Method;
5import java.lang.reflect.Proxy;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashMap;
9import java.util.Iterator;
10import java.util.Map;
11
12import biz.hammurapi.config.Context;
13import biz.hammurapi.config.DomConfigFactory;
14import biz.hammurapi.wrap.WrapperHandler;
15
16/**
17 * Decorates objects based on their type and decoration providers
18 * available. Decoration is done with dynamic proxies.
19 * @author Pavel
20 */
21public class DecoratingService {
22
23 /**
24 * Converter which delegates to convert() method.
25 */
26 public static final Decorator DECORATOR = new Decorator() {
27
28 public Object decorate(Object source) {
29 if (source==null) {
30 return null;
31 }
32 return DecoratingService.decorate(source);
33 }
34
35 };
36
37
38 /**
39 * Decorates object using static decoration providers from the object's class
40 * classloader. If there are no decorations available or object doesn't
41 * impement any interfaces, then the object is returned as-is.
42 * @param obj Object to be decorated
43 * @return Decorated object (dynamic proxy instance) or original object if
44 * no decorations are available or object doesn't implement any interfaces.
45 */
46 public static Object decorate(Object obj) {
47 return decorate(obj, null, null);
48 }
49
50 /**
51 * Decorates object using static decoration providers from the object's class
52 * classloader. If there are no decorations available or object doesn't
53 * impement any interfaces, then the object is returned as-is.
54 * @param obj Object to be decorated
55 * @param context Context for dynamic decorators.
56 * @return Decorated object (dynamic proxy instance) or original object if
57 * no decorations are available or object doesn't implement any interfaces.
58 */
59 public static Object decorate(Object obj, Context context) {
60 return decorate(obj, context, null);
61 }
62
63 /**
64 * Decorates object using providers from the given classloader.
65 * @param obj Object to decorate.
66 * @param classLoader Class loader.
67 * @return Decorated object (dynamic proxy instance) or original object if
68 * no decorations are available or object doesn't implement any interfaces.
69 */
70 public static Object decorate(Object obj, ClassLoader classLoader) {
71 return decorate(obj, null, classLoader);
72 }
73
74 /**
75 * Decorates object using given context for dynamic decorators and given class
76 * loader to load decorating providers.
77 * @param obj Object to decorate.
78 * @param context Context for dynamic decorators.
79 * @param classLoader Class loader.
80 * @return Decorated object (dynamic proxy instance) or original object if
81 * no decorations are available or object doesn't implement any interfaces.
82 */
83 public static Object decorate(final Object obj, Context context, ClassLoader classLoader) {
84 if (obj==null) {
85 return null;
86 }
87
88 final Map interfaceMap = new HashMap();
89 Class[] interfaces = WrapperHandler.getClassInterfaces(obj.getClass());
90 for (int i=0; i<interfaces.length; ++i) {
91 interfaceMap.put(interfaces[i], obj);
92 }
93
94 if (interfaceMap.isEmpty()) {
95 return obj;
96 }
97
98 if (classLoader==null) {
99 classLoader = obj.getClass().getClassLoader();
100 }
101
102 if (classLoader==null) {
103 classLoader = DecoratingService.class.getClassLoader();
104 }
105
106 ClassLoaderDecoratorsEntry clde;
107 synchronized (classLoaderEntries) {
108 clde = (ClassLoaderDecoratorsEntry) classLoaderEntries.get(classLoader);
109 if (clde == null) {
110 clde = new ClassLoaderDecoratorsEntry();
111 Iterator pit = DomConfigFactory.loadProviders(Decorator.class, classLoader);
112 while (pit.hasNext()) {
113 clde.addDecorators(pit.next());
114 }
115 classLoaderEntries.put(classLoader, clde);
116 }
117 }
118
119 int iSize = interfaceMap.size();
120 clde.collectDecorators(obj, interfaceMap, context, DECORATOR);
121 if (iSize==interfaceMap.size()) {
122 return obj;
123 }
124
125 Class[] allInterfaces = new Class[interfaceMap.size()];
126 FilterInvocationHandler fih = new FilterInvocationHandler() {
127
128 public Object getMaster() {
129 return obj;
130 }
131
132 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
133 Object target = interfaceMap.get(method.getDeclaringClass());
134 if (target==null) {
135 target = obj;
136 }
137 return method.invoke(target, args);
138 }
139
140 };
141
142 return Proxy.newProxyInstance(classLoader, allInterfaces, fih);
143 }
144
145 /**
146 * Creates decorating closure.
147 * @return Decorating closure.
148 */
149 public static Decorator getDecorator() {
150 return getDecorator(null, null);
151 }
152
153 /**
154 * Creates decorating closure.
155 * @param classLoader Class loader.
156 * @return Decorating closure.
157 */
158 public static Decorator getDecorator(ClassLoader classLoader) {
159 return getDecorator(null, classLoader);
160 }
161
162 /**
163 * Creates decorating closure.
164 * @param context Context for dynamic decorators.
165 * @return Decorating closure.
166 */
167 public static Decorator getDecorator(Context context) {
168 return getDecorator(context, null);
169 }
170
171 /**
172 * Creates decorating closure.
173 * @param context Context for dynamic decorators.
174 * @param classLoader Class loader.
175 * @return Decorating closure.
176 */
177 public static Decorator getDecorator(final Context context, final ClassLoader classLoader) {
178 return new Decorator() {
179
180 public Object decorate(Object source) {
181 return DecoratingService.decorate(source, context, classLoader);
182 }
183
184 };
185 }
186
187 private static class ClassLoaderDecoratorsEntry {
188 private static final String DECORATE = "decorate";
189
190 Collection atomicDecorators = new ArrayList();
191
192 void addDecorators(final Object provider) {
193 if (provider instanceof AtomicDecorator) {
194 atomicDecorators.add(provider);
195 } else if (provider instanceof AtomicDecoratorsBundle) {
196 atomicDecorators.addAll(((AtomicDecoratorsBundle) provider).getDecorators());
197 } else if (provider instanceof Collection) {
198 Iterator it = ((Collection) provider).iterator();
199 while (it.hasNext()) {
200 addDecorators(it.next());
201 }
202 } else { // Introspection
203 Class pClass = provider.getClass();
204 Method[] methods = pClass.getMethods();
205 for (int i=0; i<methods.length; ++i) {
206 final Method method = methods[i];
207 if (DECORATE.equals(method.getName()) && !void.class.equals(method.getReturnType())) {
208 final Class[] pTypes = method.getParameterTypes();
209 if (pTypes.length == 1) {
210 atomicDecorators.add(new AtomicDecorator() {
211
212 public Object decorate(Object source, Context context, Decorator master) {
213 try {
214 return method.invoke(provider, new Object[] {source});
215 } catch (IllegalAccessException e) {
216 throw new DecorationException(e);
217 } catch (InvocationTargetException e) {
218 throw new DecorationException(e);
219 }
220 }
221
222 public Class getSourceType() {
223 return pTypes[0];
224 }
225
226 });
227 } else if (pTypes.length == 2 && pTypes[1].equals(Decorator.class)) {
228 atomicDecorators.add(new AtomicDecorator() {
229
230 public Object decorate(Object source, Context context, Decorator master) {
231 try {
232 return method.invoke(provider, new Object[] {source, master});
233 } catch (IllegalAccessException e) {
234 throw new DecorationException(e);
235 } catch (InvocationTargetException e) {
236 throw new DecorationException(e);
237 }
238 }
239
240 public Class getSourceType() {
241 return pTypes[0];
242 }
243
244 });
245 } else if (pTypes.length == 2 && pTypes[1].equals(Context.class)) {
246 atomicDecorators.add(new AtomicDecorator() {
247
248 public Object decorate(Object source, Context context, Decorator master) {
249 try {
250 return method.invoke(provider, new Object[] {source, context});
251 } catch (IllegalAccessException e) {
252 throw new DecorationException(e);
253 } catch (InvocationTargetException e) {
254 throw new DecorationException(e);
255 }
256 }
257
258 public Class getSourceType() {
259 return pTypes[0];
260 }
261
262 });
263 } else if (pTypes.length == 3 && pTypes[1].equals(Context.class) && pTypes[1].equals(Decorator.class)) {
264 atomicDecorators.add(new AtomicDecorator() {
265
266 public Object decorate(Object source, Context context, Decorator master) {
267 try {
268 return method.invoke(provider, new Object[] {source, context, master});
269 } catch (IllegalAccessException e) {
270 throw new DecorationException(e);
271 } catch (InvocationTargetException e) {
272 throw new DecorationException(e);
273 }
274 }
275
276 public Class getSourceType() {
277 return pTypes[0];
278 }
279
280 });
281 }
282
283 }
284 }
285 }
286 }
287
288 void collectDecorators(Object obj, Map interfaceMap, Context context, Decorator master) {
289 Iterator it = atomicDecorators.iterator();
290 while (it.hasNext()) {
291 AtomicDecorator ad = (AtomicDecorator) it.next();
292 if (ad.getSourceType().isInstance(obj)) {
293 Object decoration = ad.decorate(obj, context, master);
294 if (decoration!=null) {
295 boolean cascade = false;
296 Class[] dia = WrapperHandler.getClassInterfaces(decoration.getClass());
297 for (int i=0; i<dia.length; ++i) {
298 if (!interfaceMap.containsKey(dia[i])) {
299 cascade=true;
300 interfaceMap.put(dia[i], decoration);
301 }
302 }
303 if (cascade) {
304 collectDecorators(decoration, interfaceMap, context, master);
305 }
306 }
307 }
308 }
309 }
310
311 }
312
313 /**
314 * Map of resolved converters: ClassLoader -&gt; ClassLoaderConvertersEntry.
315 */
316 private static Map classLoaderEntries = new HashMap();
317
318
319}
320