KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > loader > EJBClassPathUtils


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.loader;
25
26 import com.sun.appserv.server.util.ASClassLoaderUtil;
27 import com.sun.appserv.server.util.ASURLClassLoader;
28 import com.sun.appserv.server.util.ClassLoaderChain;
29 import com.sun.enterprise.deployment.Application;
30 import com.sun.enterprise.deployment.deploy.shared.FileArchive;
31 import com.sun.enterprise.deployment.io.ApplicationDeploymentDescriptorFile;
32 import com.sun.enterprise.deployment.util.ModuleDescriptor;
33 import com.sun.enterprise.instance.AppsManager;
34 import com.sun.enterprise.instance.BaseManager;
35 import com.sun.enterprise.server.ApplicationServer;
36 import com.sun.enterprise.server.PELaunch;
37 import com.sun.enterprise.server.ServerContext;
38 import com.sun.enterprise.util.io.FileUtils;
39 import com.sun.logging.LogDomains;
40
41 import java.io.File JavaDoc;
42 import java.io.FileInputStream JavaDoc;
43 import java.io.InputStream JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.net.MalformedURLException JavaDoc;
46 import java.net.URL JavaDoc;
47 import java.util.ArrayList JavaDoc;
48 import java.util.HashMap JavaDoc;
49 import java.util.Iterator JavaDoc;
50 import java.util.Map JavaDoc;
51 import java.util.jar.Attributes JavaDoc;
52 import java.util.jar.JarFile JavaDoc;
53 import java.util.jar.Manifest JavaDoc;
54 import java.util.List JavaDoc;
55 import java.util.logging.Level JavaDoc;
56 import java.util.logging.Logger JavaDoc;
57 import java.util.StringTokenizer JavaDoc;
58
59 import javax.enterprise.deploy.shared.ModuleType JavaDoc;
60
61 import org.xml.sax.SAXParseException JavaDoc;
62
63 /**
64  * This utility is used by EJB container during server start up to create the
65  * class loaders. It is called from the application and ejb module loaders.
66  * Deployment also calls this during ejbc.
67  *
68  * @author Jerome Dochez
69  */

70 public class EJBClassPathUtils {
71
72     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.LOADER_LOGGER);
73     /**
74      * Maps a application library URL to a ClassLoader instance.
75      * This map is used to lookup existing classloader instances when an
76      * application wants to share a library with another application.
77      */

78     private static Map JavaDoc<URL JavaDoc,ClassLoader JavaDoc> classLoaderRegistry =
79                                              new HashMap JavaDoc<URL JavaDoc,ClassLoader JavaDoc>();
80
81    /**
82      * Returns the Application class paths for the given application name.
83      *
84      * @param appName application name used to register with the config
85      * @param apps application config obj
86      *
87      * @return the ejb class paths for the given application name
88      * or empty list
89      */

90     public static List JavaDoc getAppClasspath(Application application, BaseManager apps) {
91
92         String JavaDoc appName = application.getRegistrationName();
93
94         try {
95
96           String JavaDoc appRoot = apps.getLocation(appName);
97           return getAppClassPath(application, appRoot, apps);
98           
99         } catch (Exception JavaDoc e) {
100             _logger.log(Level.SEVERE,"ejb.classpath",e);
101             return new ArrayList JavaDoc();
102         }
103     }
104     
105     public static List JavaDoc getAppClassPath(Application application, String JavaDoc appRoot, BaseManager apps) {
106         
107         List JavaDoc classpath = new ArrayList JavaDoc();
108         String JavaDoc appName = application.getRegistrationName();
109
110         try {
111
112           List JavaDoc appPath = getApplicationClassPath(application, appRoot);
113           
114           if (appPath.size() > 0) {
115               classpath.addAll(appPath);
116           }
117
118           // adds stubs dir for this application
119
classpath.add(apps.getStubLocation(appName));
120
121         } catch (Exception JavaDoc e) {
122             _logger.log(Level.SEVERE,"ejb.classpath",e);
123         }
124
125         // log the class path
126
if (_logger.isLoggable(Level.FINE)) {
127             _logger.log(Level.FINE, "[EJBClassPathUtils] EJB Class Path for ["
128                         + appName + "] is ...\n" + classpath.toString());
129         }
130
131         return classpath;
132     }
133     
134     public static List JavaDoc getModuleClasspath(String JavaDoc moduleName, String JavaDoc moduleRoot, BaseManager mgr) {
135                 
136         List JavaDoc classpath = new ArrayList JavaDoc();
137         
138         try {
139             
140             // adds the location where this module was installed
141
if (moduleRoot==null) {
142                 moduleRoot = mgr.getLocation(moduleName);
143             }
144             classpath.add(moduleRoot);
145             
146             // adds stubs dir for this stand alone ejb module
147
classpath.add( mgr.getStubLocation(moduleName) );
148             
149             classpath.addAll(getModuleClassPath(mgr.getModuleType(), moduleRoot, moduleRoot));
150         
151         } catch (Exception JavaDoc e) {
152             _logger.log(Level.SEVERE,"ejb.classpath",e);
153         }
154         
155         return classpath;
156     }
157     
158     public static List JavaDoc getModuleClassPath(ModuleType JavaDoc type, String JavaDoc moduleRoot, String JavaDoc appRoot)
159         throws IOException JavaDoc
160     {
161         
162         List JavaDoc classpath = new ArrayList JavaDoc();
163         
164         // additional class path from the manifest
165
Manifest JavaDoc mf = getManifest(moduleRoot);
166         
167         List JavaDoc manifestClassPath = getManifestClassPath(mf, appRoot);
168         classpath.addAll(manifestClassPath);
169         
170         
171         if (ModuleType.WAR.equals(type)) {
172             
173             // classes dir under WEB-INF
174
String JavaDoc classesDir = moduleRoot + File.separator + WAR_CLASSES_DIR;
175             
176             // lib dir under WEB-INF
177
String JavaDoc libDir = moduleRoot + File.separator + WAR_LIB_DIR;
178             
179             // adds the class path from the WAR module
180
// i. <war-module>/WEB-INF/classes
181
// ii. <war-module>/WEB-INF/lib/*.jar
182
List JavaDoc warClassPath = ClassLoaderUtils.getUrlList
183                     (new File[] {new File(classesDir)},
184                     new File[] {new File(libDir)} );
185                     
186              // add to the application class path
187
classpath.addAll(warClassPath);
188                     
189         } else {
190             classpath.add(moduleRoot);
191             
192             // adds the class path from the module
193
// <module>/*.jar
194
List JavaDoc moduleClassPath = ClassLoaderUtils.getUrlList
195                     (null,
196                     new File[] {new File(moduleRoot)} );
197                     classpath.addAll(moduleClassPath);
198         }
199         
200         return classpath;
201     }
202
203     /**
204      * Returns the class path for the given application with all sub-modules
205      * This is called from deployment backend.
206      *
207      * <p> WARNING: This list does not contain the stubs directory.
208      *
209      * @param appRoot application location
210      * @param appName application name used to register with the config
211      *
212      * @return class path for the given application
213      *
214      * @exception AppConfigException if an error while retrieving the
215      * application's deployment descriptor
216      */

217     public static List JavaDoc getApplicationClassPath(Application app, String JavaDoc appRoot)
218         throws IOException JavaDoc {
219         
220         List JavaDoc classpath = new ArrayList JavaDoc();
221
222         if (!app.isVirtual()) { //ear file
223

224             // first add the libraries in the library directory if it exists
225
if (app.getLibraryDirectory() != null) {
226                 String JavaDoc libPath =
227                     app.getLibraryDirectory().replace('/', File.separatorChar);
228                 List JavaDoc dirLibraries = ClassLoaderUtils.getUrlList(
229                     null, new File[] {new File(appRoot, libPath)}, true);
230                 if (dirLibraries != null && !dirLibraries.isEmpty()) {
231                    classpath.addAll(dirLibraries);
232                }
233             }
234
235             // then add the top level libraries at the app root
236
List JavaDoc rootLibraries = ClassLoaderUtils.getUrlList(
237                                     null, new File[] {new File(appRoot)});
238                                     
239             if (rootLibraries != null && !rootLibraries.isEmpty()) {
240                 classpath.addAll(rootLibraries);
241             }
242         }
243
244         for (Iterator JavaDoc modules = app.getModules(); modules.hasNext();) {
245             
246             ModuleDescriptor md = (ModuleDescriptor) modules.next();
247
248             String JavaDoc moduleUri = md.getArchiveUri();
249             String JavaDoc moduleRoot;
250             if (app.isVirtual()) {
251                 moduleRoot = appRoot;
252             } else {
253                 moduleRoot = appRoot + File.separator + FileUtils.makeFriendlyFilename(moduleUri);
254             }
255
256             classpath.addAll(getModuleClassPath(md.getModuleType(), moduleRoot, appRoot));
257         }
258         return classpath;
259     }
260
261     // ---- METHOD(S) - PRIVATE ----------------------------------------------
262

263     /**
264      * Returns the manifest file for the given root path.
265      *
266      * <xmp>
267      * Example:
268      * |--repository/
269      * | |--applications/
270      * | |--converter/
271      * | |--ejb-jar-ic_jar/ <---- rootPath
272      * | |--META-INF/
273      * | |--MANIFEST.MF
274      * </xmp>
275      *
276      * @param rootPath absolute path to the module
277      *
278      * @return the manifest file for the given module
279      */

280     public static Manifest JavaDoc getManifest(String JavaDoc rootPath) {
281
282         InputStream JavaDoc in = null;
283         Manifest JavaDoc mf = null;
284
285         // gets the input stream to the MANIFEST.MF file
286
try {
287             in = new FileInputStream JavaDoc(rootPath+File.separator+MANIFEST_ENTRY);
288
289             if (in != null) {
290                 mf = new Manifest JavaDoc(in);
291             }
292         } catch (IOException JavaDoc ioe) {
293             // ignore
294
} finally {
295             if (in != null) {
296                 try {
297                     in.close();
298                 } catch (IOException JavaDoc ioe) {
299                     // Ignore
300
}
301             }
302         }
303         return mf;
304     }
305     
306     /**
307      * Returns the class path (if any) from the given manifest file.
308      *
309      * @param manifest manifest file of an archive
310      * @param rootPath root path to the module
311      *
312      * @return a list of class paths of type java.lang.String or
313      * an empty list if given manifest is null
314      */

315     private static List JavaDoc getManifestClassPath(Manifest JavaDoc manifest,
316             String JavaDoc rootPath) {
317
318         List JavaDoc classPaths = new ArrayList JavaDoc();
319
320         if (manifest != null) {
321             Attributes JavaDoc mainAttributes = manifest.getMainAttributes();
322
323             for (Iterator JavaDoc itr=mainAttributes.keySet().iterator();
324                     itr.hasNext();) {
325
326                 Attributes.Name JavaDoc next = (Attributes.Name JavaDoc) itr.next();
327
328                 if (next.equals(Attributes.Name.CLASS_PATH)) {
329
330                     String JavaDoc classpathString = (String JavaDoc) mainAttributes.get(next);
331                     StringTokenizer JavaDoc st =
332                         new StringTokenizer JavaDoc(classpathString, " ");
333
334                     while(st.hasMoreTokens()) {
335                         String JavaDoc mc = st.nextToken();
336                         classPaths.add(rootPath+File.separator+mc);
337                     }
338                 }
339             }
340         }
341
342         return classPaths;
343     }
344  
345     public static EJBClassLoader createEJBClassLoader(String JavaDoc[] classPaths,
346                          String JavaDoc moduleRoot, String JavaDoc id, ClassLoader JavaDoc parentClassLoader,
347                          ModuleType JavaDoc moduleType) {
348         URL JavaDoc[] classPathURLs = new URL JavaDoc[0];
349         if (classPaths != null) {
350             
351             int classPathSize = classPaths.length;
352             classPathURLs = new URL JavaDoc[classPathSize];
353
354             for (int i=0; i<classPathSize; i++) {
355                 try {
356                     classPathURLs[i] = (new File(classPaths[i])).toURI().toURL();
357                 } catch (MalformedURLException JavaDoc malEx) {
358                     _logger.log(Level.WARNING,
359                                 "loader.cannot_convert_classpath_into_url",
360                                 classPaths[i]);
361                     _logger.log(Level.WARNING,"loader.exception", malEx);
362                 }
363             }
364         }
365         
366         String JavaDoc libs = null;
367         //WARs do not go via AbstractLoader and hence use ASClassLoaderUtil.getWebModuleClassPath()
368
if (moduleType.equals(ModuleType.EAR)) {
369             libs = ASClassLoaderUtil.getLibrariesForJ2EEApplication(id);
370         } else if (moduleType.equals(ModuleType.EJB)) {
371             libs = ASClassLoaderUtil.getLibrariesForEJBJars(id);
372         }
373             
374         URL JavaDoc[] deployTimeLibraries = ASClassLoaderUtil.getLibraries(libs);
375         URL JavaDoc[] resolvedLibrariesList = null;
376         
377         if (deployTimeLibraries != null) {
378             if (deployTimeLibraries.length > 0) {
379                      resolvedLibrariesList = resolveVersionConflicts(
380                                                  EJBClassPathUtils.getManifest(moduleRoot),
381                                                  deployTimeLibraries,classPaths);
382             }
383         }
384         
385         if (_logger.isLoggable(Level.FINE)) {
386             _logger.log(Level.FINE, "createEJBClassLoader :: Resolved libraries " + resolvedLibrariesList);
387         }
388         ClassLoader JavaDoc applicationLibrariesCL = createApplicationLibrariesClassLoader(
389                                                          parentClassLoader, resolvedLibrariesList, id);
390         if (_logger.isLoggable(Level.FINE)) {
391             _logger.log(Level.FINE, "- applibsCL: " + applicationLibrariesCL);
392         }
393         return createEJBClassLoader(parentClassLoader, applicationLibrariesCL, classPathURLs);
394     }
395     
396     
397     /**
398      * Checks for conflicts between application's bundled libraries and
399      * libraries specified via the deploy-time libraries attribute and returns a resolved
400      * list that does not contain any such conflicts.
401      *
402      * As per Section J2EE.8.2.3 Library conflicts section of the Java EE 5.0 specification
403      * if an application includes a bundled version of a library and the same libraries
404      * exists as an installed library , the instance of the library bundled with the application
405      * should be used in preference to any installed library.
406      *
407      * To satisfy this we remove all conflicting library from the application libraries chain.
408      *
409      * @param deployTimeLibrariesList a list of libraries specified via the
410      * deploy-time libraries attribute of the application
411      * @param mf The manifest files associated with the module.
412      * @param applicationClasspath list of libraries bundled with the application
413      * @return a resolved list of URLs that needs to be loaded by the application
414      * libraries classloader.
415      */

416     private static URL JavaDoc[] resolveVersionConflicts(Manifest JavaDoc mf, URL JavaDoc[] deployTimeLibraries,
417                                                         String JavaDoc[] applicationClasspath) {
418         try {
419             String JavaDoc appList = mf.getMainAttributes().getValue(
420                                                 Attributes.Name.EXTENSION_LIST);
421             if (appList == null) return deployTimeLibraries;
422             String JavaDoc[] appExtensions = appList.split(" " );
423             if (_logger.isLoggable(Level.FINE)) {
424                 _logger.log(Level.FINE, "Application Extension List" + appExtensions);
425             }
426             
427             List JavaDoc<URL JavaDoc> conflictingLibraries = new ArrayList JavaDoc<URL JavaDoc>();
428             for (int i = 0; i < appExtensions.length; i++) {
429                 String JavaDoc extensionName = mf.getMainAttributes().
430                                            getValue(appExtensions[i] + "-Extension-Name");
431                 String JavaDoc extensionSpecVersion = mf.getMainAttributes().
432                                            getValue(appExtensions[i] + "-Extension-Specification-Version");
433                 String JavaDoc extensionImplVersion = mf.getMainAttributes().
434                                            getValue(appExtensions[i] + "-Extension-Implementation-Version");
435                 if(bundledExtensionMatches(applicationClasspath, extensionName,
436                                                                       extensionSpecVersion,
437                                                                       extensionImplVersion )){
438                     URL JavaDoc url = isExtensionInLibraries(extensionName, deployTimeLibraries);
439                     if(url != null){
440                         conflictingLibraries.add(url);
441                     }
442                 }
443             }
444             
445             //Filter out conflicting libraries from original deployTimeLibrariesList
446
List JavaDoc<URL JavaDoc> resolvedList = new ArrayList JavaDoc<URL JavaDoc>();
447             for (int i = 0; i < deployTimeLibraries.length; i++) {
448                 if (!conflictingLibraries.contains(deployTimeLibraries[i])) {
449                     resolvedList.add(deployTimeLibraries[i]);
450                 } else {
451                     if (_logger.isLoggable(Level.FINE)) {
452                         _logger.log(Level.FINE, " conflict " + deployTimeLibraries[i] +
453                                         "being ignored");
454                     }
455                 }
456             }
457             
458             if (_logger.isLoggable(Level.FINE)) {
459                 _logger.log(Level.FINE, " Final resolved list after conflict"
460                                                   + "checking " + resolvedList);
461             }
462             return resolvedList.toArray(new URL JavaDoc[]{});
463         } catch (IOException JavaDoc ioe) {
464             _logger.log(Level.WARNING, ioe.getMessage());
465             _logger.log(Level.FINE, "Exception while checking for version " +
466                               "conflict in bundled vs provided libraries", ioe);
467         }
468         return deployTimeLibraries;
469     }
470     
471     /*
472      * Checks if the extension referred by the application is also provided in the --libraries
473      * list
474      */

475     private static URL JavaDoc isExtensionInLibraries(String JavaDoc extensionName,
476                             URL JavaDoc[] deployTimeLibrariesList) throws IOException JavaDoc {
477         for (int i = 0; i < deployTimeLibrariesList.length; i++) {
478             JarFile JavaDoc jf = new JarFile JavaDoc(deployTimeLibrariesList[i].getFile());
479             String JavaDoc extnName = jf.getManifest().getMainAttributes().getValue(
480                                                Attributes.Name.EXTENSION_NAME);
481             if (extnName.equals(extensionName)) {
482                 if (_logger.isLoggable(Level.FINE)) {
483                     _logger.log(Level.FINE, "extensionName" + extensionName +
484                    "matched by " + deployTimeLibrariesList[i] + " = CONFLICT");
485                 }
486                 return deployTimeLibrariesList[i];
487             }
488         }
489         return null;
490     }
491     
492     /**
493      * Checks if a referred extension is bundled with the application already.
494      */

495     private static boolean bundledExtensionMatches(String JavaDoc[] applicationClasspath,
496                       String JavaDoc extnName, String JavaDoc extnSpecVersion, String JavaDoc extnImplVersion) throws IOException JavaDoc {
497         for (int i = 0; i < applicationClasspath.length; i++) {
498             JarFile JavaDoc jf = new JarFile JavaDoc(applicationClasspath[i]);
499             String JavaDoc bundledExtnName = jf.getManifest().getMainAttributes().
500                                              getValue(Attributes.Name.EXTENSION_NAME);
501             String JavaDoc bundledExtnImplVersion = jf.getManifest().getMainAttributes().
502                                  getValue(Attributes.Name.IMPLEMENTATION_VERSION);
503             String JavaDoc bundledExtnSpecVersion = jf.getManifest().getMainAttributes().
504                                     getValue(Attributes.Name.SPECIFICATION_VERSION);
505             if (
506                   (extnName.equals(bundledExtnName)) &&
507                   ((extnSpecVersion != null) && (bundledExtnSpecVersion.compareTo(extnSpecVersion) >=0))
508                   && ((extnImplVersion != null) && (bundledExtnImplVersion.compareTo(extnImplVersion) >=0))
509                ) {
510                 if (_logger.isLoggable(Level.FINE)) {
511                     _logger.log(Level.FINE, "extensionName" + bundledExtnName +
512                                     "spec version: " + bundledExtnSpecVersion +
513                                     "impl version: " + bundledExtnImplVersion +
514                                     "matches within the application");
515                 }
516                 return true;
517             }
518         }
519         return false;
520     }
521     
522    
523     /**
524      * Creates the application librararies classloader, derived from the
525      * libraries attribute of the application.
526      * @return
527      */

528     private static ClassLoader JavaDoc createApplicationLibrariesClassLoader(
529                                            ClassLoader JavaDoc parentClassLoader, URL JavaDoc[] urlList, String JavaDoc moduleId) {
530         if( urlList != null ) {
531             ClassLoaderChain appChain = new ClassLoaderChain(parentClassLoader);
532             appChain.setName("Application library chain for " + moduleId);
533             for(URL JavaDoc url:urlList){
534                 ClassLoader JavaDoc urlLoader = classLoaderRegistry.get(url);
535                 //if this library has already been referred in a different application and been
536
//loaded, share this library by reusing the same classloader.
537
if(urlLoader == null) {
538                     urlLoader = new ASURLClassLoader(new URL JavaDoc[]{url}, parentClassLoader);
539                     classLoaderRegistry.put(url,urlLoader);
540                 }
541                 appChain.addToList(urlLoader);
542             }
543             
544             //Finally suffix the optional chain. The optional chain is suffixed to the appchain
545
//to enable an administrator to override libraries in the optional chain via
546
//the libraris deploy-time attribute.
547
ClassLoader JavaDoc optionalChain = PELaunch.getOptionalChain();
548             appChain.addToList(optionalChain);
549             return appChain;
550         }
551         return null;
552     }
553
554     private static EJBClassLoader createEJBClassLoader( ClassLoader JavaDoc parentClassLoader,
555                                                          ClassLoader JavaDoc appLibLoader,URL JavaDoc[] URLs ) {
556         EJBClassLoader loader = null;
557         if (appLibLoader != null) {
558             loader = new EJBClassLoader(appLibLoader);
559         } else {
560             loader = new EJBClassLoader(parentClassLoader);
561         }
562         
563         if (URLs != null) {
564             for(int i=0; i<URLs.length; i++) {
565                 loader.appendURL(URLs[i]);
566             }
567         }
568         return loader;
569     }
570
571     
572     
573     /** The manifest file name from an archive. */
574     private static final String JavaDoc MANIFEST_ENTRY =
575                     "META-INF" + File.separator + "MANIFEST.MF";
576
577     private static final String JavaDoc WAR_CLASSES_DIR =
578                     "WEB-INF"+ File.separator + "classes";
579
580     private static final String JavaDoc WAR_LIB_DIR =
581                     "WEB-INF"+ File.separator + "lib";
582 }
583
Popular Tags