1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.jomc.modlet;
32
33 import java.lang.reflect.InvocationTargetException;
34 import java.lang.reflect.Method;
35 import java.lang.reflect.Modifier;
36 import java.lang.reflect.UndeclaredThrowableException;
37 import java.text.MessageFormat;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.ResourceBundle;
41 import java.util.concurrent.Callable;
42 import java.util.concurrent.CancellationException;
43 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.Future;
45 import java.util.logging.Level;
46
47
48
49
50
51
52
53
54
55 public class DefaultServiceFactory implements ServiceFactory
56 {
57
58
59
60
61
62
63 private static final String DEFAULT_ORDINAL_PROPERTY_NAME =
64 "org.jomc.modlet.DefaultServiceFactory.defaultOrdinal";
65
66
67
68
69
70
71 private static final Integer DEFAULT_ORDINAL = 0;
72
73
74
75
76 private static volatile Integer defaultOrdinal;
77
78
79
80
81 private volatile Integer ordinal;
82
83
84
85
86 public DefaultServiceFactory()
87 {
88 super();
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public static int getDefaultOrdinal()
104 {
105 if ( defaultOrdinal == null )
106 {
107 defaultOrdinal = Integer.getInteger( DEFAULT_ORDINAL_PROPERTY_NAME, DEFAULT_ORDINAL );
108 }
109
110 return defaultOrdinal;
111 }
112
113
114
115
116
117
118
119
120 public static void setDefaultOrdinal( final Integer value )
121 {
122 defaultOrdinal = value;
123 }
124
125
126
127
128
129
130
131
132
133 public final int getOrdinal()
134 {
135 if ( this.ordinal == null )
136 {
137 this.ordinal = getDefaultOrdinal();
138 }
139
140 return this.ordinal;
141 }
142
143
144
145
146
147
148
149
150 public final void setOrdinal( final Integer value )
151 {
152 this.ordinal = value;
153 }
154
155 public <T> T createServiceObject( final ModelContext context, final Service service, final Class<T> type )
156 throws ModelException
157 {
158 if ( context == null )
159 {
160 throw new NullPointerException( "context" );
161 }
162 if ( service == null )
163 {
164 throw new NullPointerException( "service" );
165 }
166 if ( type == null )
167 {
168 throw new NullPointerException( "type" );
169 }
170
171 try
172 {
173 final Class<?> clazz = context.findClass( service.getClazz() );
174
175 if ( clazz == null )
176 {
177 throw new ModelException( getMessage( "serviceNotFound", service.getOrdinal(), service.
178 getIdentifier(),
179 service.getClazz() ) );
180
181 }
182
183 if ( !type.isAssignableFrom( clazz ) )
184 {
185 throw new ModelException( getMessage( "illegalService", service.getOrdinal(), service.
186 getIdentifier(),
187 service.getClazz(), type.getName() ) );
188
189 }
190
191 final T serviceObject = clazz.asSubclass( type ).newInstance();
192
193 if ( !service.getProperty().isEmpty() )
194 {
195 if ( context.getExecutorService() != null && service.getProperty().size() > 1 )
196 {
197 final List<Callable<Void>> tasks =
198 new ArrayList<Callable<Void>>( service.getProperty().size() );
199
200 for ( int i = 0, s0 = service.getProperty().size(); i < s0; i++ )
201 {
202 final Property p = service.getProperty().get( i );
203
204 tasks.add( new Callable<Void>()
205 {
206
207 public Void call() throws ModelException
208 {
209 initProperty( context, serviceObject, p.getName(), p.getValue() );
210 return null;
211 }
212
213 } );
214 }
215
216 for ( final Future<Void> task : context.getExecutorService().invokeAll( tasks ) )
217 {
218 task.get();
219 }
220 }
221 else
222 {
223 for ( int i = 0, s0 = service.getProperty().size(); i < s0; i++ )
224 {
225 final Property p = service.getProperty().get( i );
226 this.initProperty( context, serviceObject, p.getName(), p.getValue() );
227 }
228 }
229 }
230
231 return serviceObject;
232 }
233 catch ( final CancellationException e )
234 {
235 throw new ModelException( getMessage( "failedCreatingObject", service.getClazz() ), e );
236 }
237 catch ( final InterruptedException e )
238 {
239 throw new ModelException( getMessage( "failedCreatingObject", service.getClazz() ), e );
240 }
241 catch ( final InstantiationException e )
242 {
243 throw new ModelException( getMessage( "failedCreatingObject", service.getClazz() ), e );
244 }
245 catch ( final IllegalAccessException e )
246 {
247 throw new ModelException( getMessage( "failedCreatingObject", service.getClazz() ), e );
248 }
249 catch ( final ExecutionException e )
250 {
251 if ( e.getCause() instanceof ModelException )
252 {
253 throw (ModelException) e.getCause();
254 }
255 else if ( e.getCause() instanceof RuntimeException )
256 {
257
258
259 if ( e.getCause().getCause() instanceof ModelException )
260 {
261 throw (ModelException) e.getCause().getCause();
262 }
263 else if ( e.getCause().getCause() instanceof RuntimeException )
264 {
265 throw (RuntimeException) e.getCause().getCause();
266 }
267 else if ( e.getCause().getCause() instanceof Error )
268 {
269 throw (Error) e.getCause().getCause();
270 }
271 else if ( e.getCause().getCause() instanceof Exception )
272 {
273
274 throw new UndeclaredThrowableException( e.getCause().getCause() );
275 }
276 else
277 {
278 throw (RuntimeException) e.getCause();
279 }
280 }
281 else if ( e.getCause() instanceof Error )
282 {
283 throw (Error) e.getCause();
284 }
285 else
286 {
287
288 throw new UndeclaredThrowableException( e.getCause() );
289 }
290 }
291 }
292
293 private <T> void initProperty( final ModelContext context, final T object, final String propertyName,
294 final String propertyValue )
295 throws ModelException
296 {
297 if ( object == null )
298 {
299 throw new NullPointerException( "object" );
300 }
301 if ( propertyName == null )
302 {
303 throw new NullPointerException( "propertyName" );
304 }
305
306 try
307 {
308 final char[] chars = propertyName.toCharArray();
309
310 if ( Character.isLowerCase( chars[0] ) )
311 {
312 chars[0] = Character.toUpperCase( chars[0] );
313 }
314
315 final String methodNameSuffix = String.valueOf( chars );
316 Method getterMethod = null;
317
318 try
319 {
320 getterMethod = object.getClass().getMethod( "get" + methodNameSuffix );
321 }
322 catch ( final NoSuchMethodException e )
323 {
324 if ( context.isLoggable( Level.FINEST ) )
325 {
326 context.log( Level.FINEST, null, e );
327 }
328
329 getterMethod = null;
330 }
331
332 if ( getterMethod == null )
333 {
334 try
335 {
336 getterMethod = object.getClass().getMethod( "is" + methodNameSuffix );
337 }
338 catch ( final NoSuchMethodException e )
339 {
340 if ( context.isLoggable( Level.FINEST ) )
341 {
342 context.log( Level.FINEST, null, e );
343 }
344
345 getterMethod = null;
346 }
347 }
348
349 if ( getterMethod == null )
350 {
351 throw new ModelException( getMessage( "getterMethodNotFound", object.getClass().getName(),
352 propertyName ) );
353
354 }
355
356 final Class<?> propertyType = getterMethod.getReturnType();
357 Class<?> boxedPropertyType = propertyType;
358 Class<?> unboxedPropertyType = propertyType;
359
360 if ( Boolean.TYPE.equals( propertyType ) )
361 {
362 boxedPropertyType = Boolean.class;
363 }
364 else if ( Character.TYPE.equals( propertyType ) )
365 {
366 boxedPropertyType = Character.class;
367 }
368 else if ( Byte.TYPE.equals( propertyType ) )
369 {
370 boxedPropertyType = Byte.class;
371 }
372 else if ( Short.TYPE.equals( propertyType ) )
373 {
374 boxedPropertyType = Short.class;
375 }
376 else if ( Integer.TYPE.equals( propertyType ) )
377 {
378 boxedPropertyType = Integer.class;
379 }
380 else if ( Long.TYPE.equals( propertyType ) )
381 {
382 boxedPropertyType = Long.class;
383 }
384 else if ( Float.TYPE.equals( propertyType ) )
385 {
386 boxedPropertyType = Float.class;
387 }
388 else if ( Double.TYPE.equals( propertyType ) )
389 {
390 boxedPropertyType = Double.class;
391 }
392
393 if ( Boolean.class.equals( propertyType ) )
394 {
395 unboxedPropertyType = Boolean.TYPE;
396 }
397 else if ( Character.class.equals( propertyType ) )
398 {
399 unboxedPropertyType = Character.TYPE;
400 }
401 else if ( Byte.class.equals( propertyType ) )
402 {
403 unboxedPropertyType = Byte.TYPE;
404 }
405 else if ( Short.class.equals( propertyType ) )
406 {
407 unboxedPropertyType = Short.TYPE;
408 }
409 else if ( Integer.class.equals( propertyType ) )
410 {
411 unboxedPropertyType = Integer.TYPE;
412 }
413 else if ( Long.class.equals( propertyType ) )
414 {
415 unboxedPropertyType = Long.TYPE;
416 }
417 else if ( Float.class.equals( propertyType ) )
418 {
419 unboxedPropertyType = Float.TYPE;
420 }
421 else if ( Double.class.equals( propertyType ) )
422 {
423 unboxedPropertyType = Double.TYPE;
424 }
425
426 Method setterMethod = null;
427
428 try
429 {
430 setterMethod = object.getClass().getMethod( "set" + methodNameSuffix, boxedPropertyType );
431 }
432 catch ( final NoSuchMethodException e )
433 {
434 if ( context.isLoggable( Level.FINEST ) )
435 {
436 context.log( Level.FINEST, null, e );
437 }
438
439 setterMethod = null;
440 }
441
442 if ( setterMethod == null && !boxedPropertyType.equals( unboxedPropertyType ) )
443 {
444 try
445 {
446 setterMethod = object.getClass().getMethod( "set" + methodNameSuffix, unboxedPropertyType );
447 }
448 catch ( final NoSuchMethodException e )
449 {
450 if ( context.isLoggable( Level.FINEST ) )
451 {
452 context.log( Level.FINEST, null, e );
453 }
454
455 setterMethod = null;
456 }
457 }
458
459 if ( setterMethod == null )
460 {
461 throw new ModelException( getMessage( "setterMethodNotFound", object.getClass().getName(),
462 propertyName ) );
463
464 }
465
466 if ( boxedPropertyType.equals( Character.class ) )
467 {
468 if ( propertyValue == null || propertyValue.length() != 1 )
469 {
470 throw new ModelException( getMessage( "unsupportedCharacterValue", object.getClass().getName(),
471 propertyName ) );
472
473 }
474
475 setterMethod.invoke( object, propertyValue.charAt( 0 ) );
476 }
477 else if ( propertyValue != null )
478 {
479 invocation:
480 {
481 if ( boxedPropertyType.equals( String.class ) )
482 {
483 setterMethod.invoke( object, propertyValue );
484 break invocation;
485 }
486
487 try
488 {
489 setterMethod.invoke( object, boxedPropertyType.getConstructor( String.class ).
490 newInstance( propertyValue ) );
491
492 break invocation;
493 }
494 catch ( final NoSuchMethodException e1 )
495 {
496 if ( context.isLoggable( Level.FINEST ) )
497 {
498 context.log( Level.FINEST, null, e1 );
499 }
500 }
501
502 try
503 {
504 final Method valueOf = boxedPropertyType.getMethod( "valueOf", String.class );
505
506 if ( Modifier.isStatic( valueOf.getModifiers() )
507 && ( valueOf.getReturnType().equals( boxedPropertyType )
508 || valueOf.getReturnType().equals( unboxedPropertyType ) ) )
509 {
510 setterMethod.invoke( object, valueOf.invoke( null, propertyValue ) );
511 break invocation;
512 }
513 }
514 catch ( final NoSuchMethodException e2 )
515 {
516 if ( context.isLoggable( Level.FINEST ) )
517 {
518 context.log( Level.FINEST, null, e2 );
519 }
520 }
521
522 throw new ModelException( getMessage( "unsupportedPropertyType", object.getClass().getName(),
523 propertyName, propertyType.getName() ) );
524
525 }
526 }
527 else
528 {
529 setterMethod.invoke( object, (Object) null );
530 }
531 }
532 catch ( final IllegalAccessException e )
533 {
534 throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
535 object.getClass().getName() ), e );
536
537 }
538 catch ( final InvocationTargetException e )
539 {
540 throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
541 object.getClass().getName() ), e );
542
543 }
544 catch ( final InstantiationException e )
545 {
546 throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
547 object.getClass().getName() ), e );
548
549 }
550 }
551
552 private static String getMessage( final String key, final Object... arguments )
553 {
554 return MessageFormat.format( ResourceBundle.getBundle(
555 DefaultServiceFactory.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
556
557 }
558
559 }