KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > fortress > impl > role > ServiceMetaManager


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.impl.role;
19
20 import org.apache.avalon.fortress.MetaInfoManager;
21 import org.apache.avalon.fortress.RoleManager;
22 import org.apache.avalon.fortress.util.Service;
23 import org.apache.avalon.framework.activity.Initializable;
24
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.net.URL;
30 import java.util.*;
31
32 /**
33  * ServiceMetaManager follows some simple rules to dynamically gather all
34  * services and the meta-information into one role manager. This really gets
35  * rid of the need of multiple role managers. It uses a set of entries in your
36  * JARs to do its magic.
37  *
38  * <p><code><b>/services.list</b></code></p>
39  *
40  * <p>
41  * This lists all the services that are <em>defined</em> in this jar.
42  * </p>
43  *
44  * <p><code><b>/META-INF/services/</b><i>my.class.Name</i></code></p>
45  *
46  * <p>
47  * One entry for each service where there are implementations for a role. This
48  * follows the JAR services mechanism.
49  * </p>
50  *
51  * <p><code><i>/my/class/Implementation.meta</i></code></p>
52  *
53  * <p>
54  * There is one entry sitting right beside every implementation class. This
55  * holds all the meta information for the associated class. It is a simple
56  * properties file.
57  * </p>
58  *
59  * <h3>ANT Tasks available</h3>
60  * <p>
61  * We have a couple of ANT tasks to make this really easy. If you add this
62  * to your ANT build script (customizing it to make it work in your environment),
63  * it will make your life alot easier:
64  * </p>
65  *
66  * <pre>
67  * &lt;taskdef name="collect-metainfo" classname="org.apache.avalon.fortress.tools.ComponentMetaInfoCollector"&gt;
68  * &lt;classpath&gt;
69  * &lt;path refid="project.class.path"/&gt;
70  * &lt;pathelement path="${tools.dir}/guiapp-tools.jar"/&gt;
71  * &lt;/classpath&gt;
72  * &lt;/taskdef&gt;
73  *
74  * &lt;collect-metainfo destdir="${build.classes}"&gt;
75  * &lt;fileset dir="${src.dir}"/&gt;
76  * &lt;/collect-metainfo&gt;
77  * </pre>
78  *
79  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
80  * @version CVS $Revision: 1.12 $
81  */

82 public final class ServiceMetaManager extends AbstractMetaInfoManager implements Initializable
83 {
84     /**
85      * Create a ServiceMetaManager.
86      */

87     public ServiceMetaManager()
88     {
89         super( (MetaInfoManager) null );
90     }
91
92     /**
93      * Create a ServiceMetaManager with a parent RoleManager.
94      *
95      * @param parent
96      */

97     public ServiceMetaManager( final RoleManager parent )
98     {
99         super( parent );
100     }
101
102     /**
103      * Create a ServiceMetaManager with a parent RoleManager.
104      *
105      * @param parent
106      */

107     public ServiceMetaManager( final MetaInfoManager parent )
108     {
109         super( parent );
110     }
111
112     /**
113      * Create a ServiceMetaManager with the supplied classloader and
114      * parent RoleManager.
115      *
116      * @param parent
117      * @param loader
118      */

119     public ServiceMetaManager( final MetaInfoManager parent, final ClassLoader loader )
120     {
121         super( parent, loader );
122     }
123
124     /**
125      * Initialize the ServiceMetaManager by looking at all the services and
126      * classes available in the system.
127      *
128      * @throws Exception if there is a problem
129      */

130     public void initialize() throws Exception
131     {
132         final Set services = new HashSet();
133
134         final Enumeration enum = getLoader().getResources( "services.list" );
135         while ( enum.hasMoreElements() )
136         {
137             readEntries( services, (URL) enum.nextElement() );
138         }
139
140         final Iterator it = services.iterator();
141         while ( it.hasNext() )
142         {
143             final String role = (String) it.next();
144             getLogger().debug( "Adding service: " + role );
145             try
146             {
147                 setupImplementations( role );
148             }
149             catch ( Exception e )
150             {
151                 getLogger().debug( "Specified service '" + role + "' is not available", e );
152             }
153         }
154     }
155
156     /**
157      * Get all the implementations of a service and set up their meta
158      * information.
159      *
160      * @param role The role name we are reading implementations for.
161      *
162      * @throws ClassNotFoundException if the role or component cannot be found
163      */

164     private void setupImplementations( final String role )
165         throws ClassNotFoundException
166     {
167         final Iterator it = Service.providers( getLoader().loadClass( role ), getLoader() );
168
169         while ( it.hasNext() )
170         {
171             final String impl = ( (Class) it.next() ).getName();
172             getLogger().debug( "Reading meta info for " + impl );
173             if ( ! isAlreadyAdded( impl ) )
174             {
175                 readMeta( role, impl );
176             }
177             else
178             {
179                 // Mini-optimization: read meta info only once
180
addComponent( role, impl, null, null );
181             }
182         }
183     }
184
185     /**
186      * Read the meta information in and actually add the role.
187      *
188      * @param role
189      * @param implementation
190      */

191     private void readMeta( final String role, final String implementation )
192     {
193         final Properties meta = new Properties();
194         final List deps = new ArrayList();
195
196         try
197         {
198             final InputStream stream =
199                 getLoader().getResourceAsStream( getMetaFile( implementation ) );
200
201             if ( stream != null )
202             {
203                 meta.load( stream );
204             }
205             else
206             {
207                 getLogger().error(
208                     "Meta information for " + implementation +
209                     " unavailable, skipping this class."
210                 );
211                 return;
212             }
213         }
214         catch ( IOException ioe )
215         {
216             getLogger().error( "Could not load meta information for " +
217                 implementation + ", skipping this class." );
218             return;
219         }
220
221         try
222         {
223             URL depURL = getLoader().getResource( getDepFile( implementation ) );
224
225             if ( depURL == null )
226             {
227                 if (getLogger().isDebugEnabled())
228                 {
229                     getLogger().debug( "No dependencies for " + implementation + "." );
230                 }
231             }
232             else
233             {
234                 HashSet set = new HashSet();
235                 readEntries( set, depURL );
236                 deps.addAll( set );
237             }
238         }
239         catch ( Exception ioe )
240         {
241             getLogger().debug( "Could not load dependencies for " +
242                 implementation + ".", ioe );
243         }
244
245         addComponent( role, implementation, meta, deps );
246     }
247
248     /**
249      * Translate a class name into the meta file name.
250      *
251      * @param implementation
252      * @return String
253      */

254     private String getMetaFile( final String implementation )
255     {
256         String entry = implementation.replace( '.', '/' );
257         entry += ".meta";
258         return entry;
259     }
260
261     /**
262      * Translate a class name into the meta file name.
263      *
264      * @param implementation
265      * @return String
266      */

267     private String getDepFile( final String implementation )
268     {
269         String entry = implementation.replace( '.', '/' );
270         entry += ".deps";
271         return entry;
272     }
273
274     /**
275      * Read entries in a list file and add them all to the provided Set.
276      *
277      * @param entries
278      * @param url
279      *
280      * @throws IOException if we cannot read the entries
281      */

282     private void readEntries( final Set entries, final URL url )
283         throws IOException
284     {
285         final BufferedReader reader = new BufferedReader( new InputStreamReader( url.openStream() ) );
286
287         try
288         {
289             String entry = reader.readLine();
290             while ( entry != null )
291             {
292                 entries.add( entry );
293                 entry = reader.readLine();
294             }
295         }
296         finally
297         {
298             reader.close();
299         }
300     }
301 }
302
Popular Tags