FileDocCategorySizeDatePackage
EJBClassPathUtils.javaAPI DocGlassfish v2 API24952Tue Jul 10 10:50:18 BST 2007com.sun.enterprise.loader

EJBClassPathUtils

public class EJBClassPathUtils extends Object
This utility is used by EJB container during server start up to create the class loaders. It is called from the application and ejb module loaders. Deployment also calls this during ejbc.
author
Jerome Dochez

Fields Summary
static Logger
_logger
private static Map
classLoaderRegistry
Maps a application library URL to a ClassLoader instance. This map is used to lookup existing classloader instances when an application wants to share a library with another application.
private static final String
MANIFEST_ENTRY
The manifest file name from an archive.
private static final String
WAR_CLASSES_DIR
private static final String
WAR_LIB_DIR
Constructors Summary
Methods Summary
private static booleanbundledExtensionMatches(java.lang.String[] applicationClasspath, java.lang.String extnName, java.lang.String extnSpecVersion, java.lang.String extnImplVersion)
Checks if a referred extension is bundled with the application already.

        for (int i = 0; i < applicationClasspath.length; i++) {
            JarFile jf = new JarFile(applicationClasspath[i]);
            String bundledExtnName = jf.getManifest().getMainAttributes().
                                             getValue(Attributes.Name.EXTENSION_NAME);
            String bundledExtnImplVersion = jf.getManifest().getMainAttributes().
                                 getValue(Attributes.Name.IMPLEMENTATION_VERSION);
            String bundledExtnSpecVersion = jf.getManifest().getMainAttributes().
                                    getValue(Attributes.Name.SPECIFICATION_VERSION);
            if (   
                  (extnName.equals(bundledExtnName)) && 
                  ((extnSpecVersion != null) && (bundledExtnSpecVersion.compareTo(extnSpecVersion)  >=0)) 
                  && ((extnImplVersion != null) && (bundledExtnImplVersion.compareTo(extnImplVersion)  >=0))
               ) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "extensionName" + bundledExtnName  + 
                                    "spec version: " + bundledExtnSpecVersion + 
                                    "impl version: " + bundledExtnImplVersion + 
                                    "matches within the application");
                }
                return true;
            } 
        }
        return false;
    
private static java.lang.ClassLoadercreateApplicationLibrariesClassLoader(java.lang.ClassLoader parentClassLoader, java.net.URL[] urlList, java.lang.String moduleId)
Creates the application librararies classloader, derived from the libraries attribute of the application.

return

        if( urlList != null ) {
            ClassLoaderChain appChain = new ClassLoaderChain(parentClassLoader);
            appChain.setName("Application library chain for " + moduleId);
            for(URL url:urlList){
                try {
					ClassLoader urlLoader = classLoaderRegistry.get(url.toURI());
                //if this library has already been referred in a different application and been 
                //loaded, share this library by reusing the same classloader.
                if(urlLoader == null) {
                    urlLoader = new ASURLClassLoader(new URL[]{url}, parentClassLoader);
					    classLoaderRegistry.put(url.toURI(),urlLoader);
                }
                appChain.addToList(urlLoader);
				} catch (URISyntaxException e) {
					_logger.log(Level.FINE, "Error while resolving " + url + " to URI");
					_logger.log(Level.WARNING, e.getMessage());

				}
            }
            
            //Finally suffix the optional chain. The optional chain is suffixed to the appchain
            //to enable an administrator to override libraries in the optional chain via
            //the libraris deploy-time attribute.
            ClassLoader optionalChain = PELaunch.getOptionalChain();
            appChain.addToList(optionalChain);
            return appChain;
        }
        return null;
    
private static EJBClassLoadercreateEJBClassLoader(java.lang.ClassLoader parentClassLoader, java.lang.ClassLoader appLibLoader, java.net.URL[] URLs)

        EJBClassLoader loader = null;
        if (appLibLoader != null) {
            loader = new EJBClassLoader(appLibLoader);
        } else { 
            loader = new EJBClassLoader(parentClassLoader);
        }
        
        if (URLs != null) {            
            for(int i=0; i<URLs.length; i++) {
                loader.appendURL(URLs[i]);
            }
        }                         
        return loader;
    
public static EJBClassLoadercreateEJBClassLoader(java.lang.String[] classPaths, java.lang.String moduleRoot, java.lang.String id, java.lang.ClassLoader parentClassLoader, javax.enterprise.deploy.shared.ModuleType moduleType)

        
        URL[] classPathURLs = new URL[0];
        if (classPaths != null) {
            
            int classPathSize    = classPaths.length;
            classPathURLs   = new URL[classPathSize];

            for (int i=0; i<classPathSize; i++) {
                try {
                    classPathURLs[i] = (new File(classPaths[i])).toURI().toURL(); 
                } catch (MalformedURLException malEx) {
                    _logger.log(Level.WARNING,
                                "loader.cannot_convert_classpath_into_url",
                                classPaths[i]);
                    _logger.log(Level.WARNING,"loader.exception", malEx);
                }
            }
        }
        
        String libs = null;
        //WARs do not go via AbstractLoader and hence use ASClassLoaderUtil.getWebModuleClassPath()
        if (moduleType.equals(ModuleType.EAR)) {
            libs = ASClassLoaderUtil.getLibrariesForJ2EEApplication(id);   
        } else if (moduleType.equals(ModuleType.EJB)) {
            libs = ASClassLoaderUtil.getLibrariesForEJBJars(id);
        }
            
        URL[] deployTimeLibraries = ASClassLoaderUtil.getLibraries(libs);
        URL[] resolvedLibrariesList = null;
        
        if (deployTimeLibraries != null) {
            if (deployTimeLibraries.length > 0) {
                     resolvedLibrariesList = resolveVersionConflicts(
                                                 EJBClassPathUtils.getManifest(moduleRoot),
                                                 deployTimeLibraries,classPaths);
            }
        }
        
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "createEJBClassLoader :: Resolved libraries " + resolvedLibrariesList);
        }
        ClassLoader applicationLibrariesCL  = createApplicationLibrariesClassLoader(
                                                         parentClassLoader,  resolvedLibrariesList, id);
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "- applibsCL: " + applicationLibrariesCL);
        }
        return createEJBClassLoader(parentClassLoader, applicationLibrariesCL, classPathURLs);
    
public static java.util.ListgetAppClassPath(com.sun.enterprise.deployment.Application application, java.lang.String appRoot, com.sun.enterprise.instance.BaseManager apps)

        
        List classpath        = new ArrayList();
        String appName = application.getRegistrationName();

        try {

          List appPath = getApplicationClassPath(application, appRoot);
          
          if (appPath.size() > 0) {
              classpath.addAll(appPath);
          }

          // adds stubs dir for this application
          classpath.add(apps.getStubLocation(appName));

        } catch (Exception e) {
            _logger.log(Level.SEVERE,"ejb.classpath",e);
        }

        // log the class path
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "[EJBClassPathUtils] EJB Class Path for [" 
                        + appName + "] is ...\n" + classpath.toString());
        }

        return classpath;
    
public static java.util.ListgetAppClasspath(com.sun.enterprise.deployment.Application application, com.sun.enterprise.instance.BaseManager apps)
Returns the Application class paths for the given application name.

param
appName application name used to register with the config
param
apps application config obj
return
the ejb class paths for the given application name or empty list


                                                                         
           

        String appName = application.getRegistrationName();

        try {

          String appRoot = apps.getLocation(appName);
          return getAppClassPath(application, appRoot, apps);
          
        } catch (Exception e) {
            _logger.log(Level.SEVERE,"ejb.classpath",e);
            return new ArrayList();
        }
    
public static java.util.ListgetApplicationClassPath(com.sun.enterprise.deployment.Application app, java.lang.String appRoot)
Returns the class path for the given application with all sub-modules This is called from deployment backend.

WARNING: This list does not contain the stubs directory.

param
appRoot application location
param
appName application name used to register with the config
return
class path for the given application
exception
AppConfigException if an error while retrieving the application's deployment descriptor

        
        List classpath     = new ArrayList();        

        if (!app.isVirtual()) { //ear file

            // first add the libraries in the library directory if it exists
            if (app.getLibraryDirectory() != null) {
                String libPath = 
                    app.getLibraryDirectory().replace('/", File.separatorChar);
                List dirLibraries = ClassLoaderUtils.getUrlList(
                    null, new File[] {new File(appRoot, libPath)}, true);
                if (dirLibraries != null && !dirLibraries.isEmpty()) {
                   classpath.addAll(dirLibraries);
               }
            }

            // then add the top level libraries at the app root
            List rootLibraries = ClassLoaderUtils.getUrlList(
                                    null, new File[] {new File(appRoot)});
                                    
            if (rootLibraries != null && !rootLibraries.isEmpty()) {
                classpath.addAll(rootLibraries);
            }
        } 

        for (Iterator modules = app.getModules(); modules.hasNext();) {
            
            ModuleDescriptor md = (ModuleDescriptor) modules.next();

            String moduleUri = md.getArchiveUri();
            String moduleRoot;
            if (app.isVirtual()) {
                moduleRoot = appRoot;
            } else {
                moduleRoot = DeploymentUtils.getEmbeddedModulePath(
                    appRoot, moduleUri);
            }

            classpath.addAll(getModuleClassPath(md.getModuleType(),  moduleRoot, appRoot));             
        }
        return classpath;        
    
public static java.util.jar.ManifestgetManifest(java.lang.String rootPath)
Returns the manifest file for the given root path. Example: |--repository/ | |--applications/ | |--converter/ | |--ejb-jar-ic_jar/ <---- rootPath | |--META-INF/ | |--MANIFEST.MF

param
rootPath absolute path to the module
return
the manifest file for the given module


        InputStream in  = null;
        Manifest mf     = null;

        // gets the input stream to the MANIFEST.MF file
        try {
            in = new FileInputStream(rootPath+File.separator+MANIFEST_ENTRY);

            if (in != null) {
                mf = new Manifest(in);
            }
        } catch (IOException ioe) { 
            // ignore
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ioe) {
                    // Ignore
                }
            }
        }
        return mf;
    
private static java.util.ListgetManifestClassPath(java.util.jar.Manifest manifest, java.lang.String rootPath)
Returns the class path (if any) from the given manifest file.

param
manifest manifest file of an archive
param
rootPath root path to the module
return
a list of class paths of type java.lang.String or an empty list if given manifest is null


        List classPaths            = new ArrayList();

        if (manifest != null) {
            Attributes mainAttributes  = manifest.getMainAttributes();

            for (Iterator itr=mainAttributes.keySet().iterator();
                    itr.hasNext();) {

                Attributes.Name next = (Attributes.Name) itr.next();

                if (next.equals(Attributes.Name.CLASS_PATH)) {

                    String classpathString = (String) mainAttributes.get(next);
                    StringTokenizer st = 
                        new StringTokenizer(classpathString, " ");

                    while(st.hasMoreTokens()) {
                        String mc = st.nextToken();
                        classPaths.add(rootPath+File.separator+mc);
                    }
                }
            }
        }

        return classPaths;
    
public static java.util.ListgetModuleClassPath(javax.enterprise.deploy.shared.ModuleType type, java.lang.String moduleRoot, java.lang.String appRoot)

        
        List classpath = new ArrayList();
        
        // additional class path from the manifest
        Manifest mf = getManifest(moduleRoot);
        
        List manifestClassPath = getManifestClassPath(mf, appRoot);
        classpath.addAll(manifestClassPath);
        
        
        if (ModuleType.WAR.equals(type)) {
            
            // classes dir under WEB-INF
            String classesDir = moduleRoot + File.separator + WAR_CLASSES_DIR;
            
            // lib dir under WEB-INF
            String libDir     = moduleRoot + File.separator + WAR_LIB_DIR;
            
            // adds the class path from the WAR module
            //    i. <war-module>/WEB-INF/classes
            //   ii. <war-module>/WEB-INF/lib/*.jar
            List warClassPath = ClassLoaderUtils.getUrlList
                    (new File[] {new File(classesDir)},
                    new File[] {new File(libDir)} );
                    
             // add to the application class path
             classpath.addAll(warClassPath);
                    
        } else {
            classpath.add(moduleRoot);
            
            // adds the class path from the module
            //   <module>/*.jar
            List moduleClassPath = ClassLoaderUtils.getUrlList
                    (null,
                    new File[] {new File(moduleRoot)} );
                    classpath.addAll(moduleClassPath);
        }
        
        return classpath;            
    
public static java.util.ListgetModuleClasspath(java.lang.String moduleName, java.lang.String moduleRoot, com.sun.enterprise.instance.BaseManager mgr)

                
        List classpath = new ArrayList();
        
        try {
            
            // adds the location where this module was installed
            if (moduleRoot==null) {
                moduleRoot = mgr.getLocation(moduleName);
            }
            classpath.add(moduleRoot);
            
            // adds stubs dir for this stand alone ejb module
            classpath.add( mgr.getStubLocation(moduleName) );
            
            classpath.addAll(getModuleClassPath(mgr.getModuleType(),  moduleRoot, moduleRoot));     
        
        } catch (Exception e) {
            _logger.log(Level.SEVERE,"ejb.classpath",e);
        }        
        
        return classpath;
    
private static java.net.URLisExtensionInLibraries(java.lang.String extensionName, java.net.URL[] deployTimeLibrariesList)

        for (int i = 0; i < deployTimeLibrariesList.length; i++) {
            JarFile jf = new JarFile(deployTimeLibrariesList[i].getFile());
            String extnName = jf.getManifest().getMainAttributes().getValue(
                                               Attributes.Name.EXTENSION_NAME);
            if (extnName.equals(extensionName)) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "extensionName" + extensionName  +
                   "matched by " + deployTimeLibrariesList[i] + " = CONFLICT");
                }
                return deployTimeLibrariesList[i];
            }
        }
        return null;
    
private static java.net.URL[]resolveVersionConflicts(java.util.jar.Manifest mf, java.net.URL[] deployTimeLibraries, java.lang.String[] applicationClasspath)
Checks for conflicts between application's bundled libraries and libraries specified via the deploy-time libraries attribute and returns a resolved list that does not contain any such conflicts. As per Section J2EE.8.2.3 Library conflicts section of the Java EE 5.0 specification if an application includes a bundled version of a library and the same libraries exists as an installed library , the instance of the library bundled with the application should be used in preference to any installed library. To satisfy this we remove all conflicting library from the application libraries chain.

param
deployTimeLibrariesList a list of libraries specified via the deploy-time libraries attribute of the application
param
mf The manifest files associated with the module.
param
applicationClasspath list of libraries bundled with the application
return
a resolved list of URLs that needs to be loaded by the application libraries classloader.

        try {
            String appList = mf.getMainAttributes().getValue(
                                                Attributes.Name.EXTENSION_LIST);
            if (appList == null) return deployTimeLibraries;
            String[] appExtensions = appList.split(" " );
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Application Extension List" + appExtensions);
            }
            
            List<URL> conflictingLibraries = new ArrayList<URL>(); 
            for (int i = 0; i < appExtensions.length; i++) {
                String extensionName = mf.getMainAttributes().
                                           getValue(appExtensions[i] + "-Extension-Name");
                String extensionSpecVersion = mf.getMainAttributes().
                                           getValue(appExtensions[i] + "-Extension-Specification-Version");
                String extensionImplVersion = mf.getMainAttributes().
                                           getValue(appExtensions[i] + "-Extension-Implementation-Version");
                if(bundledExtensionMatches(applicationClasspath, extensionName, 
                                                                      extensionSpecVersion, 
                                                                      extensionImplVersion )){
                    URL url = isExtensionInLibraries(extensionName, deployTimeLibraries);
                    if(url != null){
                        conflictingLibraries.add(url);
                    }
                }
            }
            
            //Filter out  conflicting libraries from original deployTimeLibrariesList
            List<URL> resolvedList = new ArrayList<URL>();
            for (int i = 0; i < deployTimeLibraries.length; i++) {
                if (!conflictingLibraries.contains(deployTimeLibraries[i])) {
                    resolvedList.add(deployTimeLibraries[i]);
                } else {
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE, " conflict  " + deployTimeLibraries[i] +
                                        "being ignored");
                    }
                }
            }
            
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, " Final resolved list after conflict"
                                                  + "checking " + resolvedList);
            }
            return resolvedList.toArray(new URL[]{});
        } catch (IOException ioe) {
            _logger.log(Level.WARNING, ioe.getMessage());
            _logger.log(Level.FINE, "Exception while checking for version " +
                              "conflict in bundled vs provided libraries", ioe);
        }
        return deployTimeLibraries;