KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > phoenix > components > classloader > DefaultClassLoaderManager


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

8 package org.apache.avalon.phoenix.components.classloader;
9
10 import java.io.File JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.net.JarURLConnection JavaDoc;
13 import java.net.URL JavaDoc;
14 import java.security.Policy JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.Arrays JavaDoc;
17 import java.util.jar.Manifest JavaDoc;
18 import org.apache.avalon.excalibur.extension.Extension;
19 import org.apache.avalon.excalibur.i18n.ResourceManager;
20 import org.apache.avalon.excalibur.i18n.Resources;
21 import org.apache.avalon.excalibur.packagemanager.ExtensionManager;
22 import org.apache.avalon.excalibur.packagemanager.OptionalPackage;
23 import org.apache.avalon.excalibur.packagemanager.PackageManager;
24 import org.apache.avalon.framework.configuration.Configuration;
25 import org.apache.avalon.framework.configuration.ConfigurationException;
26 import org.apache.avalon.framework.context.Context;
27 import org.apache.avalon.framework.context.ContextException;
28 import org.apache.avalon.framework.context.Contextualizable;
29 import org.apache.avalon.framework.logger.AbstractLogEnabled;
30 import org.apache.avalon.framework.service.ServiceException;
31 import org.apache.avalon.framework.service.ServiceManager;
32 import org.apache.avalon.framework.service.Serviceable;
33 import org.apache.avalon.phoenix.interfaces.ClassLoaderManager;
34
35 /**
36  * Component that creates and manages the {@link ClassLoader}
37  * for an application loaded out of a <tt>.sar</tt> deployment.
38  *
39  * <p>Currently it creates a policy based on the policy declaration
40  * in the configuration. It then just creates a URLClassLoader and
41  * populates it with the specified codebase {@link URL}s.</p>
42  *
43  * <p>In the future this class will scan the manifests for "Optional
44  * Packages" formely called "Extensions" which it will add to the
45  * {@link ClassLoader}</p>
46  *
47  * @author <a HREF="mailto:peter at apache.org">Peter Donald</a>
48  * @see ClassLoaderManager
49  */

50 public class DefaultClassLoaderManager
51     extends AbstractLogEnabled
52     implements ClassLoaderManager, Contextualizable, Serviceable
53 {
54     private static final Resources REZ =
55         ResourceManager.getPackageResources( DefaultClassLoaderManager.class );
56
57     /**
58      * Component to manage "Optional Packages" aka
59      * Extensions to allow programs to declare dependencies
60      * on such extensions.
61      */

62     private PackageManager m_packageManager;
63
64     /**
65      * Parent ClassLoader for all applications
66      * aka as the "common" classloader.
67      */

68     private ClassLoader JavaDoc m_commonClassLoader;
69
70     /**
71      * Pass the Context to the Manager.
72      * It is expected that the there will be an entry
73      * <ul>
74      * <b>common.classloader</b> : ClassLoader shared betweeen
75      * container and applications</li>
76      * </ul>
77      *
78      * @param context the context
79      * @throws ContextException if context does not contain common classloader
80      */

81     public void contextualize( Context context )
82         throws ContextException
83     {
84         m_commonClassLoader = (ClassLoader JavaDoc)context.get( "common.classloader" );
85     }
86
87     public void service( final ServiceManager serviceManager )
88         throws ServiceException
89     {
90         final ExtensionManager packageRepository =
91             (ExtensionManager)serviceManager.lookup( ExtensionManager.ROLE );
92         m_packageManager = new PackageManager( packageRepository );
93     }
94
95     /**
96      * Create a {@link ClassLoader} for a specific application.
97      * See Class Javadoc for description of technique for creating
98      * {@link ClassLoader}.
99      *
100      * @param environment the configuration "environment.xml" for the application
101      * @param source the source of application. (usually the name of the .sar file
102      * or else the same as baseDirectory)
103      * @param homeDirectory the base directory of application
104      * @param workDirectory the work directory of application
105      * @param classPath the list of URLs in applications deployment
106      * @return the ClassLoader created
107      * @throws Exception if an error occurs
108      */

109     public ClassLoader JavaDoc createClassLoader( final Configuration environment,
110                                           final File JavaDoc source,
111                                           final File JavaDoc homeDirectory,
112                                           final File JavaDoc workDirectory,
113                                           final String JavaDoc[] classPath )
114         throws Exception JavaDoc
115     {
116         if( getLogger().isDebugEnabled() )
117         {
118             final String JavaDoc message =
119                 REZ.getString( "classpath-entries",
120                                Arrays.asList( classPath ) );
121             getLogger().debug( message );
122         }
123
124         //Configure policy
125
final Configuration policyConfig = environment.getChild( "policy" );
126         final Policy JavaDoc policy =
127             configurePolicy( policyConfig, homeDirectory, workDirectory );
128
129         final File JavaDoc[] extensions = getOptionalPackagesFor( classPath );
130         if( getLogger().isDebugEnabled() )
131         {
132             final String JavaDoc message =
133                 REZ.getString( "optional-packages-added", Arrays.asList( extensions ) );
134             getLogger().debug( message );
135         }
136
137         final PolicyClassLoader classLoader =
138             new PolicyClassLoader( classPath, m_commonClassLoader, policy );
139         setupLogger( classLoader, "classloader" );
140
141         for( int i = 0; i < extensions.length; i++ )
142         {
143             final URL JavaDoc url = extensions[ i ].toURL();
144             classLoader.addURL( url );
145         }
146
147         return classLoader;
148     }
149
150     /**
151      * Retrieve the files for the optional packages required by
152      * the jars in ClassPath.
153      *
154      * @param classPath the Classpath array
155      * @return the files that need to be added to ClassLoader
156      */

157     private File JavaDoc[] getOptionalPackagesFor( final String JavaDoc[] classPath )
158         throws Exception JavaDoc
159     {
160         final Manifest JavaDoc[] manifests = getManifests( classPath );
161         final Extension[] available = Extension.getAvailable( manifests );
162         final Extension[] required = Extension.getRequired( manifests );
163
164         if( getLogger().isDebugEnabled() )
165         {
166             final String JavaDoc message1 =
167                 REZ.getString( "available-extensions",
168                                Arrays.asList( available ) );
169             getLogger().debug( message1 );
170             final String JavaDoc message2 =
171                 REZ.getString( "required-extensions",
172                                Arrays.asList( required ) );
173             getLogger().debug( message2 );
174         }
175
176         final ArrayList JavaDoc dependencies = new ArrayList JavaDoc();
177         final ArrayList JavaDoc unsatisfied = new ArrayList JavaDoc();
178
179         m_packageManager.scanDependencies( required,
180                                            available,
181                                            dependencies,
182                                            unsatisfied );
183
184         if( 0 != unsatisfied.size() )
185         {
186             final int size = unsatisfied.size();
187             for( int i = 0; i < size; i++ )
188             {
189                 final Extension extension = (Extension)unsatisfied.get( i );
190                 final Object JavaDoc[] params = new Object JavaDoc[]
191                 {
192                     extension.getExtensionName(),
193                     extension.getSpecificationVendor(),
194                     extension.getSpecificationVersion(),
195                     extension.getImplementationVendor(),
196                     extension.getImplementationVendorID(),
197                     extension.getImplementationVersion(),
198                     extension.getImplementationURL()
199                 };
200                 final String JavaDoc message = REZ.format( "missing.extension", params );
201                 getLogger().warn( message );
202             }
203
204             final String JavaDoc message =
205                 REZ.getString( "unsatisfied.extensions", new Integer JavaDoc( size ) );
206             throw new Exception JavaDoc( message );
207         }
208
209         final OptionalPackage[] packages =
210             (OptionalPackage[])dependencies.toArray( new OptionalPackage[ 0 ] );
211         return OptionalPackage.toFiles( packages );
212     }
213
214     private Manifest JavaDoc[] getManifests( final String JavaDoc[] classPath )
215         throws Exception JavaDoc
216     {
217         final ArrayList JavaDoc manifests = new ArrayList JavaDoc();
218
219         for( int i = 0; i < classPath.length; i++ )
220         {
221             final String JavaDoc element = classPath[ i ];
222
223             if( element.endsWith( ".jar" ) )
224             {
225                 try
226                 {
227                     final URL JavaDoc url = new URL JavaDoc( "jar:" + element + "!/" );
228                     final JarURLConnection JavaDoc connection = (JarURLConnection JavaDoc)url.openConnection();
229                     final Manifest JavaDoc manifest = connection.getManifest();
230                     if( null != manifest )
231                     {
232                         manifests.add( manifest );
233                     }
234                 }
235                 catch( final IOException JavaDoc ioe )
236                 {
237                     final String JavaDoc message = REZ.getString( "bad-classpath-entry", element );
238                     getLogger().warn( message );
239                     throw new Exception JavaDoc( message );
240                 }
241             }
242         }
243
244         return (Manifest JavaDoc[])manifests.toArray( new Manifest JavaDoc[ 0 ] );
245     }
246
247     /**
248      * Setup policy based on configuration data.
249      *
250      * @param configuration the configuration data
251      * @param baseDirectory the applications base directory
252      * @throws ConfigurationException if an error occurs
253      */

254     private Policy JavaDoc configurePolicy( final Configuration configuration,
255                                     final File JavaDoc baseDirectory,
256                                     final File JavaDoc workDirectory )
257         throws ConfigurationException
258     {
259         final DefaultPolicy policy =
260             new DefaultPolicy( baseDirectory, workDirectory );
261         policy.enableLogging( getLogger() );
262         policy.configure( configuration );
263         return policy;
264     }
265 }
266
Popular Tags