KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > loom > components > util > verifier > ComponentVerifier


1 /*
2  * Copyright (C) The Loom Group. All rights reserved.
3  *
4  * This software is published under the terms of the Loom
5  * Software License version 1.1, a copy of which has been included
6  * with this distribution in the LICENSE.txt file.
7  */

8 package org.codehaus.loom.components.util.verifier;
9
10 import java.lang.reflect.Constructor JavaDoc;
11 import java.lang.reflect.Modifier JavaDoc;
12
13 import org.apache.avalon.framework.activity.Disposable;
14 import org.apache.avalon.framework.activity.Initializable;
15 import org.apache.avalon.framework.activity.Startable;
16 import org.apache.avalon.framework.activity.Suspendable;
17 import org.apache.avalon.framework.component.Composable;
18 import org.apache.avalon.framework.component.Recomposable;
19 import org.apache.avalon.framework.configuration.Configurable;
20 import org.apache.avalon.framework.configuration.Reconfigurable;
21 import org.apache.avalon.framework.context.Contextualizable;
22 import org.apache.avalon.framework.context.Recontextualizable;
23 import org.apache.avalon.framework.logger.LogEnabled;
24 import org.apache.avalon.framework.parameters.Parameterizable;
25 import org.apache.avalon.framework.parameters.Reparameterizable;
26 import org.apache.avalon.framework.service.Serviceable;
27
28 import org.codehaus.spice.salt.i18n.ResourceManager;
29 import org.codehaus.spice.salt.i18n.Resources;
30 import org.codehaus.dna.AbstractLogEnabled;
31 import org.codehaus.metaclass.Attributes;
32 import org.codehaus.metaclass.model.Attribute;
33
34 /**
35  * Utility class to help verify that component respects the rules of an Avalon component.
36  *
37  * @author Peter Donald
38  * @version $Revision: 1.2 $ $Date: 2004/05/01 12:48:34 $
39  */

40 public class ComponentVerifier extends AbstractLogEnabled
41 {
42     /**
43      * I18n utils.
44      */

45     private static final Resources REZ =
46         ResourceManager.getPackageResources( ComponentVerifier.class );
47
48     /**
49      * Constant for array of 0 classes. Saves recreating array everytime look up constructor with no args.
50      */

51     private static final Class JavaDoc[] EMPTY_TYPES = new Class JavaDoc[0];
52
53     /**
54      * The interfaces representing lifecycle stages.
55      */

56     private static final Class JavaDoc[] FRAMEWORK_CLASSES = new Class JavaDoc[]
57     {
58         LogEnabled.class,
59         Contextualizable.class,
60         Recontextualizable.class,
61         Composable.class,
62         Recomposable.class,
63         Serviceable.class,
64         Configurable.class,
65         Reconfigurable.class,
66         Parameterizable.class,
67         Reparameterizable.class,
68         Initializable.class,
69         Startable.class,
70         Suspendable.class,
71         Disposable.class
72     };
73
74     /**
75      * Verfiy that specified components designate classes that implement the advertised interfaces.
76      *
77      * @param name the name of component
78      * @param type the component type
79      *
80      * @throws java.lang.Exception if an error occurs
81      */

82     public void verifyType( final String JavaDoc name, final Class JavaDoc type )
83         throws Exception JavaDoc
84     {
85         final Attribute attribute =
86             Attributes.getAttribute( type, "dna.component" );
87         if( null == attribute )
88         {
89             final String JavaDoc msg = "Legacy? component " + name
90                 + " does not specify correct metadata. Skipping type verification";
91
92             getLogger().warn( msg );
93
94 // final String message =
95
// "Component " + name + " does not specify correct metadata";
96
// throw new Exception( message );
97
}
98         final Class JavaDoc[] interfaces = getServiceClasses( name, type );
99         verifyComponent( name, type, interfaces, false );
100     }
101
102     /**
103      * Verify that the supplied implementation class and service classes are valid for a component.
104      *
105      * @param name the name of component
106      * @param implementation the implementation class of component
107      * @param services the classes representing services
108      * @param buildable if true will verify that it is instantiateable via class.newInstance(). May not be required
109      * for some components that are created via a factory.
110      *
111      * @throws java.lang.Exception if error thrown on failure and component fails check
112      */

113     public void verifyComponent( final String JavaDoc name,
114                                  final Class JavaDoc implementation,
115                                  final Class JavaDoc[] services,
116                                  final boolean buildable )
117         throws Exception JavaDoc
118     {
119         if( buildable )
120         {
121             verifyClass( name, implementation );
122         }
123         verifyLifecycles( name, implementation );
124         verifyServices( name, services );
125         verifyImplementsServices( name, implementation, services );
126     }
127
128     /**
129      * Verify that the supplied implementation implements the specified services.
130      *
131      * @param name the name of component
132      * @param implementation the class representign component
133      * @param services the services that the implementation must provide
134      *
135      * @throws java.lang.Exception if error thrown on failure and component fails check
136      */

137     public void verifyImplementsServices( final String JavaDoc name,
138                                           final Class JavaDoc implementation,
139                                           final Class JavaDoc[] services )
140         throws Exception JavaDoc
141     {
142         for( int i = 0; i < services.length; i++ )
143         {
144             if( !services[i].isAssignableFrom( implementation ) )
145             {
146                 final String JavaDoc message =
147                     REZ.format( "verifier.noimpl-service.error",
148                                 name,
149                                 implementation.getName(),
150                                 services[i].getName() );
151                 throw new Exception JavaDoc( message );
152             }
153         }
154     }
155
156     /**
157      * Verify that the supplied class is a valid class for a Component.
158      *
159      * @param name the name of component
160      * @param clazz the class representing component
161      *
162      * @throws java.lang.Exception if error thrown on failure and component fails check
163      */

164     public void verifyClass( final String JavaDoc name,
165                              final Class JavaDoc clazz )
166         throws Exception JavaDoc
167     {
168         verifyNoArgConstructor( name, clazz );
169         verifyNonAbstract( name, clazz );
170         verifyNonArray( name, clazz );
171         verifyNonInterface( name, clazz );
172         verifyNonPrimitive( name, clazz );
173         verifyPublic( name, clazz );
174     }
175
176     /**
177      * Verify that the supplied classes are valid classes for a service.
178      *
179      * @param name the name of component
180      * @param classes the classes representign services
181      *
182      * @throws java.lang.Exception if error thrown on failure and component fails check
183      */

184     public void verifyServices( final String JavaDoc name,
185                                 final Class JavaDoc[] classes )
186         throws Exception JavaDoc
187     {
188         for( int i = 0; i < classes.length; i++ )
189         {
190             verifyService( name, classes[i] );
191         }
192     }
193
194     /**
195      * Verify that the supplied class is a valid class for a service.
196      *
197      * @param name the name of component
198      * @param clazz the class representign service
199      *
200      * @throws java.lang.Exception if error thrown on failure and component fails check
201      */

202     public void verifyService( final String JavaDoc name,
203                                final Class JavaDoc clazz )
204         throws Exception JavaDoc
205     {
206         verifyServiceIsaInterface( name, clazz );
207         verifyServiceIsPublic( name, clazz );
208         verifyServiceNotALifecycle( name, clazz );
209     }
210
211     /**
212      * Verify that the implementation class does not implement incompatible lifecycle interfaces.
213      *
214      * @param name the name of component
215      * @param implementation the implementation class
216      *
217      * @throws java.lang.Exception if error thrown on failure and component fails check
218      */

219     public void verifyLifecycles( final String JavaDoc name,
220                                   final Class JavaDoc implementation )
221         throws Exception JavaDoc
222     {
223         final boolean composable =
224             Composable.class.isAssignableFrom( implementation ) ||
225             Recomposable.class.isAssignableFrom( implementation );
226         final boolean serviceable = Serviceable.class.isAssignableFrom( implementation );
227         if( serviceable && composable )
228         {
229             final String JavaDoc message =
230                 REZ.format( "verifier.incompat-serviceable.error",
231                             name,
232                             implementation.getName() );
233             throw new Exception JavaDoc( message );
234         }
235
236         final boolean configurable =
237             Configurable.class.isAssignableFrom( implementation ) ||
238             Reconfigurable.class.isAssignableFrom( implementation );
239         final boolean parameterizable =
240             Parameterizable.class.isAssignableFrom( implementation ) ||
241             Reparameterizable.class.isAssignableFrom( implementation );
242         if( parameterizable && configurable )
243         {
244             final String JavaDoc message =
245                 REZ.format( "verifier.incompat-config.error",
246                             name,
247                             implementation.getName() );
248             throw new Exception JavaDoc( message );
249         }
250     }
251
252     /**
253      * Verify that the service implemented by specified component is an interface.
254      *
255      * @param name the name of component
256      * @param clazz the class representign service
257      *
258      * @throws java.lang.Exception if error thrown on failure and component fails check
259      */

260     public void verifyServiceIsaInterface( final String JavaDoc name,
261                                            final Class JavaDoc clazz )
262         throws Exception JavaDoc
263     {
264         if( !clazz.isInterface() )
265         {
266             final String JavaDoc message =
267                 REZ.format( "verifier.non-interface-service.error",
268                             name,
269                             clazz.getName() );
270             throw new Exception JavaDoc( message );
271         }
272     }
273
274     /**
275      * Verify that the service implemented by specified component is public.
276      *
277      * @param name the name of component
278      * @param clazz the class representign service
279      *
280      * @throws java.lang.Exception if error thrown on failure and component fails check
281      */

282     public void verifyServiceIsPublic( final String JavaDoc name,
283                                        final Class JavaDoc clazz )
284         throws Exception JavaDoc
285     {
286         final boolean isPublic =
287             Modifier.isPublic( clazz.getModifiers() );
288         if( !isPublic )
289         {
290             final String JavaDoc message =
291                 REZ.format( "verifier.non-public-service.error",
292                             name,
293                             clazz.getName() );
294             throw new Exception JavaDoc( message );
295         }
296     }
297
298     /**
299      * Verify that the service implemented by specified component does not extend any lifecycle interfaces.
300      *
301      * @param name the name of component
302      * @param clazz the class representign service
303      *
304      * @throws java.lang.Exception if error thrown on failure and component fails check
305      */

306     public void verifyServiceNotALifecycle( final String JavaDoc name,
307                                             final Class JavaDoc clazz )
308         throws Exception JavaDoc
309     {
310         for( int i = 0; i < FRAMEWORK_CLASSES.length; i++ )
311         {
312             final Class JavaDoc lifecycle = FRAMEWORK_CLASSES[i];
313             if( lifecycle.isAssignableFrom( clazz ) )
314             {
315                 final String JavaDoc message =
316                     REZ.format( "verifier.service-isa-lifecycle.error",
317                                 name,
318                                 clazz.getName(),
319                                 lifecycle.getName() );
320                 throw new Exception JavaDoc( message );
321             }
322         }
323     }
324
325     /**
326      * Verify that the component has a no-arg aka default constructor.
327      *
328      * @param name the name of component
329      * @param clazz the class representign component
330      *
331      * @throws java.lang.Exception if error thrown on failure and component fails check
332      */

333     public void verifyNoArgConstructor( final String JavaDoc name,
334                                         final Class JavaDoc clazz )
335         throws Exception JavaDoc
336     {
337         try
338         {
339             final Constructor JavaDoc ctor = clazz.getConstructor( EMPTY_TYPES );
340             if( !Modifier.isPublic( ctor.getModifiers() ) )
341             {
342                 final String JavaDoc message =
343                     REZ.format( "verifier.non-public-ctor.error",
344                                 name,
345                                 clazz.getName() );
346                 throw new Exception JavaDoc( message );
347             }
348         }
349         catch( final NoSuchMethodException JavaDoc nsme )
350         {
351             final String JavaDoc message =
352                 REZ.format( "verifier.missing-noargs-ctor.error",
353                             name,
354                             clazz.getName() );
355             throw new Exception JavaDoc( message );
356         }
357     }
358
359     /**
360      * Verify that the component is not represented by abstract class.
361      *
362      * @param name the name of component
363      * @param clazz the class representign component
364      *
365      * @throws java.lang.Exception if error thrown on failure and component fails check
366      */

367     public void verifyNonAbstract( final String JavaDoc name,
368                                    final Class JavaDoc clazz )
369         throws Exception JavaDoc
370     {
371         final boolean isAbstract =
372             Modifier.isAbstract( clazz.getModifiers() );
373         if( isAbstract )
374         {
375             final String JavaDoc message =
376                 REZ.format( "verifier.abstract-class.error",
377                             name,
378                             clazz.getName() );
379             throw new Exception JavaDoc( message );
380         }
381     }
382
383     /**
384      * Verify that the component is not represented by abstract class.
385      *
386      * @param name the name of component
387      * @param clazz the class representign component
388      *
389      * @throws java.lang.Exception if error thrown on failure and component fails check
390      */

391     public void verifyPublic( final String JavaDoc name,
392                               final Class JavaDoc clazz )
393         throws Exception JavaDoc
394     {
395         final boolean isPublic =
396             Modifier.isPublic( clazz.getModifiers() );
397         if( !isPublic )
398         {
399             final String JavaDoc message =
400                 REZ.format( "verifier.nonpublic-class.error",
401                             name,
402                             clazz.getName() );
403             throw new Exception JavaDoc( message );
404         }
405     }
406
407     /**
408      * Verify that the component is not represented by primitive class.
409      *
410      * @param name the name of component
411      * @param clazz the class representign component
412      *
413      * @throws java.lang.Exception if error thrown on failure and component fails check
414      */

415     public void verifyNonPrimitive( final String JavaDoc name,
416                                     final Class JavaDoc clazz )
417         throws Exception JavaDoc
418     {
419         if( clazz.isPrimitive() )
420         {
421             final String JavaDoc message =
422                 REZ.format( "verifier.primitive-class.error",
423                             name,
424                             clazz.getName() );
425             throw new Exception JavaDoc( message );
426         }
427     }
428
429     /**
430      * Verify that the component is not represented by interface class.
431      *
432      * @param name the name of component
433      * @param clazz the class representign component
434      *
435      * @throws java.lang.Exception if error thrown on failure and component fails check
436      */

437     public void verifyNonInterface( final String JavaDoc name,
438                                     final Class JavaDoc clazz )
439         throws Exception JavaDoc
440     {
441         if( clazz.isInterface() )
442         {
443             final String JavaDoc message =
444                 REZ.format( "verifier.interface-class.error",
445                             name,
446                             clazz.getName() );
447             throw new Exception JavaDoc( message );
448         }
449     }
450
451     /**
452      * Verify that the component is not represented by an array class.
453      *
454      * @param name the name of component
455      * @param clazz the class representign component
456      *
457      * @throws java.lang.Exception if error thrown on failure and component fails check
458      */

459     public void verifyNonArray( final String JavaDoc name,
460                                 final Class JavaDoc clazz )
461         throws Exception JavaDoc
462     {
463         if( clazz.isArray() )
464         {
465             final String JavaDoc message =
466                 REZ.format( "verifier.array-class.error",
467                             name,
468                             clazz.getName() );
469             throw new Exception JavaDoc( message );
470         }
471     }
472
473     /**
474      * Retrieve an array of Classes for all the services that a Component offers. This method also makes sure all
475      * services offered are interfaces.
476      *
477      * @param name the name of component
478      * @param type the component type
479      *
480      * @return an array of Classes for all the services
481      *
482      * @throws java.lang.Exception if an error occurs
483      */

484     protected Class JavaDoc[] getServiceClasses( final String JavaDoc name,
485                                          final Class JavaDoc type )
486         throws Exception JavaDoc
487     {
488         final ClassLoader JavaDoc classLoader = type.getClassLoader();
489         final Attribute[] attributes =
490             Attributes.getAttributes( type, "dna.service" );
491         final Class JavaDoc[] classes = new Class JavaDoc[attributes.length];
492         for( int i = 0; i < attributes.length; i++ )
493         {
494             final String JavaDoc classname = attributes[i].getParameter( "type" );
495             try
496             {
497                 classes[i] = classLoader.loadClass( classname );
498             }
499             catch( final Throwable JavaDoc t )
500             {
501                 final String JavaDoc message =
502                     "Unable to load service class \"" +
503                     classname +
504                     "\" for Component named \"" +
505                     name + "\". (Reason: " + t + ").";
506                 throw new Exception JavaDoc( message );
507             }
508         }
509
510         return classes;
511     }
512 }
513
Popular Tags