KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > fortress > tools > Component


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  *
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.avalon.fortress.tools;
19
20 import com.thoughtworks.qdox.model.*;
21 import org.apache.avalon.fortress.MetaInfoEntry;
22 import org.apache.avalon.fortress.util.dag.Vertex;
23 import org.apache.tools.ant.BuildException;
24
25 import java.io.File JavaDoc;
26 import java.io.FileOutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.util.*;
29
30 /**
31  * Represents a component, and output the meta information.
32  *
33  * @author <a HREF="mailto:dev@avalon.apache.org">The Avalon Team</a>
34  * @version CVS $Revision: 1.20 $ $Date: 2004/02/28 15:16:27 $
35  */

36 final class Component
37 {
38     private static final String JavaDoc SINGLE_THREADED = "org.apache.avalon.framework.thread.SingleThreaded";
39     private static final String JavaDoc THREAD_SAFE = "org.apache.avalon.framework.thread.ThreadSafe";
40     private static final String JavaDoc POOLABLE = "org.apache.avalon.excalibur.pool.Poolable";
41     private static final String JavaDoc RECYCLABLE = "org.apache.avalon.excalibur.pool.Recyclable";
42     private static final String JavaDoc SERVICE_MANAGER = "org.apache.avalon.framework.service.ServiceManager";
43
44     static final String JavaDoc ATTR_TYPE = "type";
45     static final String JavaDoc ATTR_NAME = "name";
46
47     private static final String JavaDoc TAG_SERVICE = "avalon.service";
48     private static final String JavaDoc TAG_DEPENDENCY = "avalon.dependency";
49     private static final String JavaDoc TAG_LIFESTYLE = "x-avalon.lifestyle";
50     private static final String JavaDoc TAG_HANDLER = "fortress.handler";
51     private static final String JavaDoc TAG_INFO = "x-avalon.info";
52     private static final String JavaDoc TAG_NAME = "fortress.name";
53
54     private static final String JavaDoc META_NAME = "x-avalon.name";
55
56     private static final String JavaDoc METH_SERVICE = "service";
57
58     /** The repository of components. */
59     static final Set m_repository = new HashSet();
60
61     private final JavaClass m_javaClass;
62     private final Properties m_attributes;
63     private final List m_dependencies;
64     private final Vertex m_vertex;
65     private final List m_dependencyNames;
66     private final List m_serviceNames;
67
68     /**
69      * Initialize a service with the type name.
70      *
71      * @param javaClass
72      */

73     public Component( final JavaClass javaClass )
74     {
75         if ( javaClass == null ) throw new NullPointerException JavaDoc( "javaClass" );
76
77         m_javaClass = javaClass;
78         m_attributes = new Properties();
79         m_dependencies = new ArrayList( 10 );
80         m_vertex = new Vertex( this );
81         m_dependencyNames = new ArrayList( 10 );
82         m_serviceNames = new ArrayList( 10 );
83
84         final DocletTag[] tags = javaClass.getTagsByName( TAG_SERVICE );
85         for ( int t = 0; t < tags.length; t++ )
86         {
87             if ( tags[t].getNamedParameter( Component.ATTR_TYPE ) == null )
88             {
89                 throw new BuildException( "The \"type\" tag is missing from the "
90                     + "\"@" + TAG_SERVICE + "\" meta tag in "
91                     + javaClass.getName() );
92             }
93
94             final String JavaDoc serviceName = resolveClassName( m_javaClass.getParentSource(),
95                     tags[t].getNamedParameter( Component.ATTR_TYPE ) );
96             m_serviceNames.add( serviceName );
97         }
98
99         discoverLifecycleType();
100         discoverNameInfo();
101         discoverDependencies();
102
103         m_repository.add( this );
104     }
105
106     /**
107      * Recursively discover dependencies from the local class hierarchy. This does not, and cannot
108      * discover dependencies from classes from other JARs.
109      */

110     private void discoverDependencies()
111     {
112         JavaClass currClass = m_javaClass;
113
114         while ( currClass != null && discoverDependencies( currClass ) )
115         {
116             currClass = currClass.getSuperJavaClass();
117         }
118     }
119
120     /**
121      * Discover the dependencies that this component class requires.
122      *
123      * @param fromClass The JavaClass object to gather the dependency set from.
124      */

125     private boolean discoverDependencies( final JavaClass fromClass )
126     {
127         boolean isSuccessful = true;
128
129         JavaMethod[] methods = fromClass.getMethods();
130         for ( int i = 0; i < methods.length; i++ )
131         {
132             if ( methods[i].getName().equals( METH_SERVICE ) )
133             {
134                 if ( methods[i].getParameters().length == 1 && methods[i].getParameters()[0].getType().getValue().equals( SERVICE_MANAGER ) )
135                 {
136                     DocletTag[] dependencies = methods[i].getTagsByName( TAG_DEPENDENCY );
137                     for ( int d = 0; d < dependencies.length; d++ )
138                     {
139                         if ( dependencies[d].getNamedParameter( ATTR_TYPE ) == null )
140                         {
141                             throw new BuildException( "The \"type\" tag is missing from a "
142                                 + "\"@" + TAG_DEPENDENCY + "\" meta tag of the " + METH_SERVICE
143                                 + " method in " + fromClass.getName() );
144                         }
145
146                         String JavaDoc type = resolveClassName( fromClass.getParentSource(),
147                                 dependencies[d].getNamedParameter( ATTR_TYPE ) );
148                         //String optional = dependencies[d].getNamedParameter("optional");
149

150                         if ( null == type )
151                         {
152                             isSuccessful = false;
153                         }
154                         else
155                         {
156                             m_dependencyNames.add( type );
157                         }
158                     }
159                 }
160             }
161         }
162
163         return isSuccessful;
164     }
165
166     private void discoverNameInfo()
167     {
168         DocletTag avalonConfigName = m_javaClass.getTagByName( TAG_INFO );
169         if ( null == avalonConfigName ) avalonConfigName = m_javaClass.getTagByName( TAG_NAME );
170
171         String JavaDoc name = MetaInfoEntry.createShortName(m_javaClass.getName());
172
173         if ( avalonConfigName != null )
174         {
175             name = avalonConfigName.getNamedParameter( ATTR_NAME );
176         }
177
178         setAttribute( META_NAME, name );
179     }
180
181     private void discoverLifecycleType()
182     {
183         final DocletTag avalonLifecycle = m_javaClass.getTagByName( TAG_LIFESTYLE );
184         final DocletTag fortressHandler = m_javaClass.getTagByName( TAG_HANDLER );
185         String JavaDoc lifecycle = null;
186         String JavaDoc handler = null;
187
188         if ( avalonLifecycle == null && fortressHandler == null )
189         {
190             final Type[] interfaces = m_javaClass.getImplements();
191             for ( int i = 0; i < interfaces.length && handler != null; i++ )
192             {
193                 if ( interfaces[i].getClass().getName().equals( THREAD_SAFE ) )
194                 {
195                     handler = MetaInfoEntry.THREADSAFE_HANDLER;
196                 }
197                 else if ( interfaces[i].getClass().getName().equals( POOLABLE ) ||
198                         interfaces[i].getClass().getName().equals( RECYCLABLE ) )
199                 {
200                     handler = MetaInfoEntry.POOLABLE_HANDLER;
201                 }
202                 else if ( interfaces[i].getClass().getName().equals( SINGLE_THREADED ) )
203                 {
204                     handler = MetaInfoEntry.FACTORY_HANDLER;
205                 }
206             }
207         }
208
209         if ( null != avalonLifecycle ) // lifecycle specified directly
210
{
211             lifecycle = stripQuotes( avalonLifecycle.getNamedParameter( ATTR_TYPE ) );
212         }
213         else if ( null != fortressHandler ) // handler specified directly
214
{
215             handler = stripQuotes( fortressHandler.getNamedParameter( ATTR_TYPE ) );
216         }
217         else // no lifecycle or handler specified, and no inspection match
218
{
219             handler = MetaInfoEntry.PER_THREAD_HANDLER;
220         }
221
222         if ( null != lifecycle ) setAttribute( TAG_LIFESTYLE, lifecycle );
223         if ( null != handler ) setAttribute( TAG_HANDLER, handler );
224     }
225
226     /**
227      * Get the type name.
228      *
229      * @return String
230      */

231     public String JavaDoc getType()
232     {
233         return m_javaClass.getFullyQualifiedName();
234     }
235
236     public Iterator getDependencyNames()
237     {
238         return m_dependencyNames.iterator();
239     }
240
241     public Iterator getServiceNames()
242     {
243         return m_serviceNames.iterator();
244     }
245
246     /**
247      * Add a dependency to this type.
248      *
249      * @param service The name of the service that depends on this.
250      */

251     public void addDependency( Service service )
252     {
253         if ( !m_dependencies.contains( service ) )
254         {
255             m_dependencies.add( service );
256         }
257     }
258
259     public Vertex getVertex()
260     {
261         if ( m_vertex.getDependencies().size() != 0 )
262         {
263             Iterator it = m_dependencies.iterator();
264             while ( it.hasNext() )
265             {
266                 Service service = (Service) it.next();
267
268                 Iterator cit = service.getComponents();
269                 while ( cit.hasNext() )
270                 {
271                     Component component = (Component) cit.next();
272                     m_vertex.addDependency( component.getVertex() );
273                 }
274             }
275         }
276         return m_vertex;
277     }
278
279     /**
280      * Set the component attribute.
281      *
282      * @param name The name of the attribute
283      * @param value The attribute value
284      */

285     public void setAttribute( final String JavaDoc name, final String JavaDoc value )
286     {
287         m_attributes.setProperty( name, value );
288     }
289
290     /**
291      * Output the meta information.
292      *
293      * @param rootDir
294      * @throws IOException
295      */

296     public void serialize( final File JavaDoc rootDir ) throws IOException JavaDoc
297     {
298         final String JavaDoc fileName = getType().replace( '.', '/' ).concat( ".meta" );
299         final String JavaDoc depsName = getType().replace( '.', '/' ).concat( ".deps" );
300         File JavaDoc output = new File JavaDoc( rootDir, fileName );
301         FileOutputStream JavaDoc writer = null;
302
303         try
304         {
305             writer = new FileOutputStream JavaDoc( output );
306             m_attributes.store( writer, "Meta information for " + getType() );
307
308             if ( m_dependencies.size() > 0 )
309             {
310                 writer.close();
311                 output = new File JavaDoc( rootDir, depsName );
312                 writer = new FileOutputStream JavaDoc( output );
313
314                 Iterator it = m_dependencies.iterator();
315                 while ( it.hasNext() )
316                 {
317                     Service service = (Service) it.next();
318                     String JavaDoc name = service.getType() + "\n";
319                     writer.write( name.getBytes() );
320                 }
321             }
322         }
323         finally
324         {
325             if ( null != writer )
326             {
327                 writer.close();
328             }
329         }
330     }
331
332     private String JavaDoc stripQuotes( final String JavaDoc value )
333     {
334         if ( null == value ) return null;
335         if ( value.length() < 2 ) return value;
336
337         String JavaDoc retVal = value.trim();
338
339         if ( retVal.startsWith( "\"" ) && retVal.endsWith( "\"" ) )
340         {
341             retVal = retVal.substring( 1, retVal.length() - 1 );
342         }
343
344         return retVal;
345     }
346
347     /**
348      * Resolve the classname from the "@avalon.service" javadoc tags.
349      *
350      * @param serviceName The service type name
351      * @return The fully qualified class name
352      */

353     protected String JavaDoc resolveClassName( final JavaSource sourceCode, final String JavaDoc serviceName )
354     {
355         if ( null == sourceCode )
356         {
357             return null;
358         }
359         if ( null == serviceName )
360         {
361             // This should be checked by the caller so that a message which better
362
// describes the problem in a given context can be given.
363
throw new IllegalStateException JavaDoc( "The serviceName parameter was null." );
364         }
365
366         final String JavaDoc className = stripQuotes( serviceName );
367
368         if ( className != null || className.length() > 0 )
369         {
370             if ( className.indexOf( '.' ) < 0 )
371             {
372                 String JavaDoc checkName = checkPackage(sourceCode, sourceCode.getPackage(), className);
373                 if ( ! checkName.equals(className) ) return checkName;
374
375                 String JavaDoc[] imports = sourceCode.getImports();
376                 for ( int t = 0; t < imports.length; t++ )
377                 {
378                     checkName = checkImport( sourceCode, imports[t], className);
379                     if ( ! checkName.equals( className ) ) return checkName;
380                 }
381             }
382         }
383
384         return className;
385     }
386
387     private String JavaDoc checkImport ( final JavaSource sourceCode, final String JavaDoc type, final String JavaDoc className)
388     {
389         final String JavaDoc tail = type.substring( type.lastIndexOf( '.' ) + 1 );
390
391         if ( tail.equals( className ) )
392         {
393             return type;
394         }
395         else if ( tail.equals( "*" ) )
396         {
397             final String JavaDoc pack = type.substring( 0, type.lastIndexOf( '.' ) );
398
399             String JavaDoc checkName = checkPackage( sourceCode, pack, className );
400             if ( !checkName.equals( className ) ) return checkName;
401         }
402
403         return className;
404     }
405
406     private String JavaDoc checkPackage( final JavaSource sourceCode, final String JavaDoc pack, final String JavaDoc serviceName )
407     {
408         String JavaDoc className = serviceName;
409         final JavaClass klass = sourceCode.getClassLibrary().getClassByName( pack + "." + serviceName );
410         if ( null != klass )
411             className = klass.getFullyQualifiedName();
412         return className;
413     }
414 }
415
Popular Tags