FileDocCategorySizeDatePackage
ExtensionFileManager.javaAPI DocGlassfish v2 API20716Sat Jul 14 21:24:00 BST 2007com.sun.enterprise.appclient.jws

ExtensionFileManager

public class ExtensionFileManager extends Object
Manages a data structure of all extension jars known to the app server.

This class builds a map of extension name to an instance of the inner class Extension that records information about that extension jar. An Extension is created for every jar file in any of the directories specified by java.ext.dirs.

Later, a caller can use the findExtensionTransitiveClosure method, passing a jar file manifest's main attributes and receiving back a List of Extension objects representing all extension jars referenced directly or indirectly from that jar.

author
tjquinn

Fields Summary
private static final String
EXT_DIRS_PROPERTY_NAME
the property name that points to extension directories
private Logger
_logger
private com.sun.enterprise.util.i18n.StringManager
localStrings
local strings manager
private Map
extensionFileInfo
private Vector
extensionFileDirs
Records directories specified in java.ext.dirs
Constructors Summary
public ExtensionFileManager()
Creates a new instance of ExtensionFileManager

throws
IOException in case of errors searching extension directories for jars

            
                         
        
        extensionFileDirs = buildExtensionFileDirs();
        extensionFileInfo = buildExtensionFileEntries(extensionFileDirs);
    
Methods Summary
private voidaddExtJarsFromDirectory(java.util.Map map, int extensionDirNumber, java.io.File extDir)
Adds entries for the extension files from one directory to the indicated Map.

param
extensionFilesMap map of each extension name to its Extension
param
extensionDirNumber the ordinal number of the directory being processed
param
extDirPath the current directory being processed
throws
IOException in case of error scanning for jar files

        File [] extJars = extDir.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".jar");
            }
          });
        if (extJars != null) {
            for (File file : extJars) {
                Extension entry = buildExtensionForJar(file, extensionDirNumber);
                if (entry != null) {
                    map.put(entry.extensionKey, entry);
                }
            }
        }
     
private java.util.VectorbuildExtensionFileDirs()
Constructs the collection of File objects, one for each extension directory.

return
Vector containing a File for each extension directory

        Vector<File> result = new Vector<File>();
        
        String extDirs = System.getProperty(EXT_DIRS_PROPERTY_NAME);
        StringTokenizer stkn = new StringTokenizer(extDirs, File.pathSeparator);

        while (stkn.hasMoreTokens()) {
            String extensionDirPath = stkn.nextToken();
            result.add(new File(extensionDirPath));
        }
        return result;
    
private java.util.MapbuildExtensionFileEntries(java.util.Vector dirs)
Constructs the collection of extension files known to the app server.

param
dirs the directories in which to search for extension jar files
return
Map mapping the extension name and spec version to the extension jar entry
throws
IOException in case of errors processing jars in the extension directories


        /*
         *For each extension directory, collect all jar files
         *and add an entry (containing File and spec version string) for each 
         *file into the data structure.
         */
         Map<ExtensionKey,Extension> result = new HashMap<ExtensionKey,Extension>();
         
         for (int i = 0; i < dirs.size(); i++) {
            addExtJarsFromDirectory(result, i, dirs.get(i));
        }
        return result;
     
private com.sun.enterprise.appclient.jws.ExtensionFileManager$ExtensionbuildExtensionForJar(java.io.File file, int extDirectoryNumber)
Creates an extension Extension for a jar file if the jar is in fact an extension.

param
jarFile a File object for the jar to use
param
extDirectoryNumber the ordinal number of the directory in java.ext.dirs being scanned
return
Extension for the jar if the jar has an extension name; null otherwise
throws
IOException in case of errors working with the file

        Extension result = null;
        JarFile jarFile = null;
        try {
            jarFile = new JarFile(file);
            ExtensionKey key = getDefinedExtensionKey(jarFile);
            if (key != null) {
                result = new Extension(key, file, extDirectoryNumber);
            }
            return result;
        } finally {
            if (jarFile != null) {
                jarFile.close();
            }
        }
    
private java.util.SetextensionsToFiles(java.util.Set extensions)
Returns a Set of File objects corresponding to the supplied set of Extensions.

param
extensions set of Extension the files of which are of interest
return
set of File, one File for each Extension in the input set

        Set<File> result = new HashSet<File>();
        for (Extension e : extensions) {
            result.add(e.file);
        }
        return result;
    
public java.util.SetfindExtensionTransitiveClosure(java.io.File anchorDir, java.util.jar.Attributes mainAttrs)
Constructs a List of Extension objects corresponding to jars required to satisfy an extension chain.

The transitive closure includes any extensions required by the initial jar, its Class-Path jars, and any extensions required by extensions.

param
anchorDir the directory relative to which Class-Path manifest entries are evaluated (if relative)
param
mainAttrs the main attributes from a jar file whose extensions are to be satisfied
return
List containing an Extension object for each required jar
throws
IOException in case of errors building the extension jar file data structure

        
        Set<Extension> result = new HashSet<Extension>();

        Vector<File> filesToProcess = new Vector<File>();
        
        filesToProcess.addAll(getClassPathJars(anchorDir, mainAttrs));
        
        Set<Extension> extensionsUsedByApp = getReferencedExtensions(mainAttrs);
        result.addAll(extensionsUsedByApp);
        filesToProcess.addAll(extensionsToFiles(extensionsUsedByApp));
        
        /**
         *Do not use the for/each construct next because the loop may add
         *elements to the vector and for/each would through a concurrent
         *modification exception.
         */
        for (int i = 0; i < filesToProcess.size(); i++) {
            File nextFile = filesToProcess.get(i);
            /*
             *The Class-Path entry might point to a directory.  If so, skip it
             *because directories do not support extensions.
             */
            if (nextFile.exists() && nextFile.isDirectory()) {
                continue;
            }
            
            try {
                JarFile nextJarFile = new JarFile(nextFile);
                try {
                    Attributes attrs = getMainAttrs(nextJarFile);
                    Set<Extension> newExtensions = getReferencedExtensions(attrs);
                    result.addAll(newExtensions);
                    filesToProcess.addAll(extensionsToFiles(newExtensions));
                } finally {
                    if (nextJarFile != null) {
                        nextJarFile.close();
                    }
                }
            } catch (Exception e) {
                _logger.log(Level.WARNING, localStrings.getString("jws.extension.error", nextFile.getAbsolutePath()), e);
            }
        }
        return result;
    
private java.util.ListgetClassPathJars(java.io.File anchorDir, java.util.jar.Attributes mainAttrs)
Returns the Files corresponding to the Class-Path entries (if any) in a Jar file's main attributes.

param
anchorDir the directory to which relative Class-Path entries are resolved
param
mainAttrs the jar file's main attributes (which would contain Class-Path entries if there are any)

        List<File> result = new LinkedList<File>();
        String classPathList = mainAttrs.getValue(Attributes.Name.CLASS_PATH);
        if (classPathList != null) {
            StringTokenizer stkn = new StringTokenizer(classPathList, " ");
            while (stkn.hasMoreTokens()) {
                String classPathJarPath = stkn.nextToken();
                File classPathJarFile = new File(classPathJarPath);
                if ( ! classPathJarFile.isAbsolute()) {
                    classPathJarFile = new File(anchorDir, classPathJarPath);
                }
                result.add(classPathJarFile);
            }
        }
        return result;
    
private com.sun.enterprise.appclient.jws.ExtensionFileManager$ExtensionKeygetDefinedExtensionKey(java.util.jar.JarFile jarFile)
Returns the ExtensionKey for the extension which the specified JarFile provides (if any).

param
jarFile the JarFile which may be an extension jar
returns
the ExtensionKey for the extension if this jar is one; null otherwise
throws
IOException in case of error getting the jar file's main attributes

        ExtensionKey result = null;
        
        Attributes mainAttrs = getMainAttrs(jarFile);
        if (mainAttrs != null) {
            String extName = mainAttrs.getValue(Attributes.Name.EXTENSION_NAME);
            if (extName != null) {
                String specVersion = mainAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
                result = new ExtensionKey(extName, specVersion);
            }
        }
        
        return result;
    
public java.util.MapgetExtensionFileEntries()

        return extensionFileInfo;
    
private java.util.jar.AttributesgetMainAttrs(java.util.jar.JarFile jarFile)
Returns the main attributes (if any) object from a jar file.

param
jarFile the JarFile of interest
return
Attributes object for the jar file's main attributes.
throws
IOException in case of error getting the Jar file's manifest

        Attributes result = null;
        
        Manifest mf = jarFile.getManifest();
        if (mf != null) {
            result = mf.getMainAttributes();
        }
        return result;
    
private java.util.SetgetReferencedExtensionKeys(java.util.jar.Attributes mainAttrs)
Returns the ExtensionKeys for the extension jars referenced by the specified main attributes

param
mainAttrs the main attributes from a jar file that may refer to extension jars
return
Set of ExtensionKey, one key or each distinct extension jar that is referenced

        Set<ExtensionKey> result = new HashSet<ExtensionKey>();
        
        if (mainAttrs != null) {
            String extensionList = mainAttrs.getValue(Attributes.Name.EXTENSION_LIST);
            if (extensionList != null) {
                StringTokenizer stkn = new StringTokenizer(extensionList, " ");
                while (stkn.hasMoreTokens()) {
                    /*
                     *For each extension jar in this jar's list, create a new
                     *ExtensionKey using the name and spec version.
                     */
                    String token = stkn.nextToken().trim();
                    String extName = mainAttrs.getValue(token + "-" + Attributes.Name.EXTENSION_NAME);
                    String specVersion = mainAttrs.getValue(token + "-" + Attributes.Name.SPECIFICATION_VERSION);
                    ExtensionKey key = new ExtensionKey(extName, specVersion);
                    result.add(key);
                }
            }
        }
        return result;
    
private java.util.SetgetReferencedExtensions(java.util.jar.Attributes mainAttrs)
Returns a Set of Extensions that are referenced by the jar file whose main attributes are passed.

param
mainAttrs the main attributes from a jar file's manifest
return
Set of Extension objects corresponding to the extensions referenced by the attributes
throws
IOException if an extension jar is required but not found

        Set<Extension> result = new HashSet<Extension>();
        Set<ExtensionKey> extensionKeys = getReferencedExtensionKeys(mainAttrs);

        for (ExtensionKey key : extensionKeys) {
            if ( ! result.contains(key)) {
                Extension extension = extensionFileInfo.get(key);

                /*
                 *Add this extension only if it does not already appear 
                 *in the result collection.  In that case, also add the
                 *file to the collection of files to be processed.
                 */
                if (extension != null) {
                    result.add(extension);
                } else {
                    throw new IOException("Jar file requires the extension " + key + " but it is not in the known extensions " + extensionFileInfo);
                }
            }
        }
        return result;