KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.ArrayList JavaDoc;
11 import java.util.Stack JavaDoc;
12
13 import org.codehaus.loom.components.util.info.ComponentInfo;
14 import org.codehaus.loom.components.util.info.DependencyDescriptor;
15 import org.codehaus.loom.components.util.info.ServiceDescriptor;
16 import org.codehaus.loom.components.util.metadata.DependencyDirective;
17 import org.codehaus.loom.components.util.profile.ComponentProfile;
18 import org.codehaus.spice.salt.i18n.ResourceManager;
19 import org.codehaus.spice.salt.i18n.Resources;
20 import org.codehaus.dna.AbstractLogEnabled;
21
22 /**
23  * This Class verifies that Sars are valid. It performs a number of checks to
24  * make sure that the Sar represents a valid application and excluding runtime
25  * errors will start up validly. Some of the checks it performs include;
26  *
27  * <ul> <li>Verify names of Components contain only letters, digits or the '_'
28  * character.</li> <li>Verify that the names of the Components are unique to the
29  * Assembly.</li> <li>Verify that the specified dependeny mapping correspond to
30  * dependencies specified in ComponentInfo files.</li> <li>Verify that the
31  * inter-Component dependendencies are valid. This essentially means that if
32  * Component A requires Service S from Component B then Component B must provide
33  * Service S.</li> <li>Verify that there are no circular dependendencies between
34  * components.</li> <li>Verify that the Class objects for component implement
35  * the service interfaces.</li> </ul>
36  *
37  * @author Peter Donald
38  * @version $Revision: 1.3 $ $Date: 2004/11/07 21:46:44 $
39  */

40 public class AssemblyVerifier
41     extends AbstractLogEnabled
42 {
43     private static final Resources REZ =
44         ResourceManager.getPackageResources( AssemblyVerifier.class );
45
46     /**
47      * Validate and Verify the specified assembly (ie organization of
48      * components). See the Class Javadocs for the rules and regulations of
49      * assembly.
50      *
51      * @param components the Components that make up assembly
52      * @throws Exception if an error occurs
53      */

54     public void verifyAssembly( final ComponentProfile[] components )
55         throws Exception JavaDoc
56     {
57         String JavaDoc message;
58
59         message = REZ.getString( "assembly.valid-names.notice" );
60         getLogger().info( message );
61         verifyValidNames( components );
62
63         message = REZ.getString( "assembly.unique-names.notice" );
64         getLogger().info( message );
65         checkNamesUnique( components );
66
67         message = REZ.getString( "assembly.dependencies-mapping.notice" );
68         getLogger().info( message );
69         verifyValidDependencies( components );
70
71         message = REZ.getString( "assembly.dependency-references.notice" );
72         getLogger().info( message );
73         verifyDependencyReferences( components );
74
75         message = REZ.getString( "assembly.nocircular-dependencies.notice" );
76         getLogger().info( message );
77         verifyNoCircularDependencies( components );
78     }
79
80     /**
81      * Verfiy that all Components have the needed dependencies specified
82      * correctly.
83      *
84      * @param components the ComponentEntry objects for the components
85      * @throws Exception if an error occurs
86      */

87     public void verifyValidDependencies( final ComponentProfile[] components )
88         throws Exception JavaDoc
89     {
90         for( int i = 0; i < components.length; i++ )
91         {
92             verifyDependenciesMap( components[ i ] );
93         }
94     }
95
96     /**
97      * Verfiy that there are no circular references between Components.
98      *
99      * @param components the ComponentEntry objects for the components
100      * @throws Exception if an circular dependency error occurs
101      */

102     protected void verifyNoCircularDependencies(
103         final ComponentProfile[] components )
104         throws Exception JavaDoc
105     {
106         for( int i = 0; i < components.length; i++ )
107         {
108             final ComponentProfile component = components[ i ];
109
110             final Stack JavaDoc stack = new Stack JavaDoc();
111             stack.push( component );
112             verifyNoCircularDependencies( component, components, stack );
113             stack.pop();
114         }
115     }
116
117     /**
118      * Verfiy that there are no circular references between Components.
119      *
120      * @param component ???
121      * @param components the ComponentEntry objects for the components
122      * @param stack the ???
123      * @throws Exception if an error occurs
124      */

125     protected void verifyNoCircularDependencies(
126         final ComponentProfile component,
127         final ComponentProfile[] components,
128         final Stack JavaDoc stack )
129         throws Exception JavaDoc
130     {
131         final ComponentProfile[] dependencies = getDependencies( component,
132                                                                  components );
133         for( int i = 0; i < dependencies.length; i++ )
134         {
135             final ComponentProfile dependency = dependencies[ i ];
136             if( stack.contains( dependency ) )
137             {
138                 final String JavaDoc trace = getDependencyTrace( dependency, stack );
139                 final String JavaDoc message =
140                     REZ.format( "assembly.circular-dependency.error",
141                                 component.getTemplate().getName(),
142                                 trace );
143                 throw new Exception JavaDoc( message );
144             }
145
146             stack.push( dependency );
147             verifyNoCircularDependencies( dependency, components, stack );
148             stack.pop();
149         }
150     }
151
152     /**
153      * Get a string defining path from top of stack till it reaches specified
154      * component.
155      *
156      * @param component the component
157      * @param stack the Stack
158      * @return the path of dependency
159      */

160     protected String JavaDoc getDependencyTrace( final ComponentProfile component,
161                                          final Stack JavaDoc stack )
162     {
163         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
164         sb.append( "[ " );
165
166         final String JavaDoc name = component.getTemplate().getName();
167         final int size = stack.size();
168         final int top = size - 1;
169         for( int i = top; i >= 0; i-- )
170         {
171             final ComponentProfile other = (ComponentProfile)stack.get( i );
172             if( top != i )
173             {
174                 sb.append( ", " );
175             }
176             sb.append( other.getTemplate().getName() );
177
178             if( other.getTemplate().getName().equals( name ) )
179             {
180                 break;
181             }
182         }
183
184         sb.append( ", " );
185         sb.append( name );
186
187         sb.append( " ]" );
188         return sb.toString();
189     }
190
191     /**
192      * Get array of dependencies for specified Component from specified
193      * Component array.
194      *
195      * @param component the component to get dependencies of
196      * @param components the total set of components in application
197      * @return the dependencies of component
198      */

199     protected ComponentProfile[] getDependencies(
200         final ComponentProfile component,
201         final ComponentProfile[] components )
202     {
203         final ArrayList JavaDoc dependencies = new ArrayList JavaDoc();
204         final DependencyDirective[] deps =
205             component.getTemplate().getDependencies();
206
207         for( int i = 0; i < deps.length; i++ )
208         {
209             final String JavaDoc name = deps[ i ].getProviderName();
210             final ComponentProfile other = getComponentProfile( name,
211                                                                 components );
212             dependencies.add( other );
213         }
214
215         return (ComponentProfile[])dependencies.toArray(
216             new ComponentProfile[ 0 ] );
217     }
218
219     /**
220      * Verfiy that the inter-Component dependencies are valid.
221      *
222      * @param components the ComponentProfile objects for the components
223      * @throws Exception if an error occurs
224      */

225     protected void verifyDependencyReferences(
226         final ComponentProfile[] components )
227         throws Exception JavaDoc
228     {
229         for( int i = 0; i < components.length; i++ )
230         {
231             verifyDependencyReferences( components[ i ], components );
232         }
233     }
234
235     /**
236      * Verfiy that the inter-Component dependencies are valid for specified
237      * Component.
238      *
239      * @param component the ComponentProfile object for the component
240      * @param others the ComponentProfile objects for the other components
241      * @throws Exception if an error occurs
242      */

243     protected void verifyDependencyReferences(
244         final ComponentProfile component,
245         final ComponentProfile[] others )
246         throws Exception JavaDoc
247     {
248         final ComponentInfo info = component.getInfo();
249         final DependencyDirective[] dependencies = component.getTemplate()
250             .getDependencies();
251
252         for( int i = 0; i < dependencies.length; i++ )
253         {
254             final DependencyDirective dependency = dependencies[ i ];
255             final String JavaDoc providerName = dependency.getProviderName();
256             final String JavaDoc key = dependency.getKey();
257             final String JavaDoc type = info.getDependency( key ).getComponentType();
258
259             //Get the other component that is providing service
260
final ComponentProfile provider = getComponentProfile(
261                 providerName, others );
262             if( null == provider )
263             {
264                 final String JavaDoc message =
265                     REZ.format( "assembly.missing-dependency.error",
266                                 key,
267                                 providerName,
268                                 component.getTemplate().getName() );
269                 throw new Exception JavaDoc( message );
270             }
271
272             //make sure that the component offers service
273
//that user expects it to be providing
274
final ComponentInfo providerInfo = provider.getInfo();
275             final ServiceDescriptor[] services = providerInfo.getServices();
276             if( !hasMatchingService( type, services ) )
277             {
278                 final String JavaDoc message =
279                     REZ.format( "assembly.dependency-missing-service.error",
280                                 providerName,
281                                 type,
282                                 component.getTemplate().getName() );
283                 throw new Exception JavaDoc( message );
284             }
285         }
286     }
287
288     /**
289      * Get component with specified name from specified Component array.
290      *
291      * @param name the name of component to get
292      * @param components the array of components to search
293      * @return the Component if found, else null
294      */

295     protected ComponentProfile getComponentProfile( final String JavaDoc name,
296                                                     final ComponentProfile[] components )
297     {
298         for( int i = 0; i < components.length; i++ )
299         {
300             ComponentProfile ComponentProfile = components[ i ];
301             if( ComponentProfile.getTemplate().getName().equals( name ) )
302             {
303                 return components[ i ];
304             }
305         }
306
307         return null;
308     }
309
310     /**
311      * Verify that the names of the specified Components are valid.
312      *
313      * @param components the Components Profile
314      * @throws Exception if an error occurs
315      */

316     protected void verifyValidNames( final ComponentProfile[] components )
317         throws Exception JavaDoc
318     {
319         for( int i = 0; i < components.length; i++ )
320         {
321             ComponentProfile ComponentProfile = components[ i ];
322             final String JavaDoc name = ComponentProfile.getTemplate().getName();
323             if( !isValidName( name ) )
324             {
325                 final String JavaDoc message =
326                     REZ.format( "assembly.bad-name.error", name );
327                 throw new Exception JavaDoc( message );
328             }
329         }
330     }
331
332     /**
333      * Return true if specified name is valid. Valid names consist of letters,
334      * digits or the '_' character.
335      *
336      * @param name the name to check
337      * @return true if valid, false otherwise
338      */

339     protected boolean isValidName( final String JavaDoc name )
340     {
341         final int size = name.length();
342         for( int i = 0; i < size; i++ )
343         {
344             final char ch = name.charAt( i );
345
346             if( !Character.isLetterOrDigit( ch ) && '-' != ch )
347             {
348                 return false;
349             }
350         }
351
352         return true;
353     }
354
355     /**
356      * Verify that the names of the specified components and listeners are
357      * unique. It is not valid for the same name to be used in multiple
358      * components.
359      *
360      * @param components the Components
361      * @throws Exception if an error occurs
362      */

363     protected void checkNamesUnique( final ComponentProfile[] components )
364         throws Exception JavaDoc
365     {
366         for( int i = 0; i < components.length; i++ )
367         {
368             ComponentProfile ComponentProfile = components[ i ];
369             final String JavaDoc name = ComponentProfile.getTemplate().getName();
370             verifyUniqueName( components, name, i );
371         }
372     }
373
374     /**
375      * Verfify that specified name is unique among the specified components.
376      *
377      * @param components the array of components to check
378      * @param name the name of component
379      * @param index the index of component in array (so we can skip it)
380      * @throws Exception if names are not unique
381      */

382     private void verifyUniqueName( final ComponentProfile[] components,
383                                    final String JavaDoc name,
384                                    final int index )
385         throws Exception JavaDoc
386     {
387         for( int i = 0; i < components.length; i++ )
388         {
389             ComponentProfile ComponentProfile = components[ i ];
390             final String JavaDoc other =
391                 ComponentProfile.getTemplate().getName();
392             if( index != i && other.equals( name ) )
393             {
394                 final String JavaDoc message =
395                     REZ.format( "assembly.duplicate-name.error", name );
396                 throw new Exception JavaDoc( message );
397             }
398         }
399     }
400
401     /**
402      * Retrieve a list of DependencyDirective objects for ComponentProfile and
403      * verify that there is a 1 to 1 map with dependencies specified in
404      * ComponentInfo.
405      *
406      * @param component the ComponentProfile describing the component
407      * @throws Exception if an error occurs
408      */

409     protected void verifyDependenciesMap( final ComponentProfile component )
410         throws Exception JavaDoc
411     {
412         //Make sure all dependency entries specified in config file are valid
413
final DependencyDirective[] dependencySet =
414             component.getTemplate().getDependencies();
415
416         for( int i = 0; i < dependencySet.length; i++ )
417         {
418             final String JavaDoc key = dependencySet[ i ].getKey();
419             final ComponentInfo info = component.getInfo();
420             final DependencyDescriptor descriptor = info.getDependency( key );
421
422             //If there is no dependency descriptor in ComponentInfo then
423
//user has specified an uneeded dependency.
424
if( null == descriptor )
425             {
426                 final String JavaDoc name = dependencySet[ i ].getProviderName();
427                 final String JavaDoc message =
428                     REZ.format( "assembly.unknown-dependency.error",
429                                 name,
430                                 key,
431                                 component.getTemplate().getName() );
432                 throw new Exception JavaDoc( message );
433             }
434         }
435
436         //Make sure all dependencies in ComponentInfo file are satisfied
437
final ComponentInfo info = component.getInfo();
438         final DependencyDescriptor[] dependencies = info.getDependencies();
439         for( int i = 0; i < dependencies.length; i++ )
440         {
441             final DependencyDescriptor dependency = dependencies[ i ];
442             final DependencyDirective dependencyMetaData =
443                 component.getTemplate().getDependency( dependency.getKey() );
444
445             //If there is no metaData then the user has failed
446
//to specify a needed dependency.
447
if( null == dependencyMetaData && !dependency.isOptional() )
448             {
449                 final String JavaDoc message =
450                     REZ.format( "assembly.unspecified-dependency.error",
451                                 dependency.getKey(),
452                                 component.getTemplate().getName() );
453                 throw new Exception JavaDoc( message );
454             }
455         }
456     }
457
458     /**
459      * Return true if specified service reference matches any of the candidate
460      * services.
461      *
462      * @param type the service type
463      * @param candidates an array of candidate services
464      * @return true if candidate services contains a service that matches
465      * specified service, false otherwise
466      */

467     protected boolean hasMatchingService( final String JavaDoc type,
468                                           final ServiceDescriptor[] candidates )
469     {
470         for( int i = 0; i < candidates.length; i++ )
471         {
472             final String JavaDoc otherClassname = candidates[ i ].getType();
473             if( otherClassname.equals( type ) )
474             {
475                 return true;
476             }
477         }
478
479         return false;
480     }
481 }
482
Popular Tags