FileDocCategorySizeDatePackage
ClientJarMakerUtils.javaAPI DocGlassfish v2 API20975Fri Jul 20 08:52:50 BST 2007com.sun.enterprise.deployment.backend

ClientJarMakerUtils

public class ClientJarMakerUtils extends Object
This class is responsible for creating an appclient jar file that will be used by the appclient container to run the appclients for the deployed application.
author
deployment dev team

Fields Summary
private static final Logger
logger
Constructors Summary
Methods Summary
private static voidaddClassPathElementsFromManifest(java.util.jar.Manifest mf, java.net.URI appURI, java.net.URI moduleParentURI, java.util.List libraries)

        for (String element : getClassPathElementsFromManifest(mf, appURI, moduleParentURI)) {
            libraries.add(element);
        }
    
static voidaddClassPathElementsFromManifestClassPaths(java.io.File appArchive, java.util.List libraries)
Adds class path elements to the list of libraries based on the Class-Path entries from the manifests of JARs already in the list.

param
appArchive the file where the application resides
param
libraries the List which contains JARs already and will be modified

        boolean isFine = logger.isLoggable(Level.FINE);
        URI appArchiveURI = appArchive.toURI();
        
        // Use a ListIterator so we can add elements during the iteration.
        for (ListIterator<String> it = libraries.listIterator(); it.hasNext();) {
            String entry = it.next();
            if (entry.endsWith(".jar")) {
                // Record class path elements added from this JAR
                StringBuilder elementsAdded = isFine ? new StringBuilder() : null;
                
                File jarFile = new File(appArchive, entry);
                /*
                 * Make sure this library exists before trying to open it to 
                 * process its manifest Class-Path entries.
                 */
                if ( ! jarFile.exists()) {
                    if (isFine) {
                        logger.fine("Skipping manifest Class-Path processing for non-existent library " + jarFile.getAbsolutePath());
                    }
                    continue;
                }
                JarFile jar = new JarFile(jarFile);
                Manifest mf = jar.getManifest();
                List<String> classPathLibs = getClassPathElementsFromManifest(
                        mf, appArchiveURI, appArchiveURI.resolve(jarFile.toURI()));
                /*
                 * Add each class path element from the manifest to the list of 
                 * libraries if it does not already exist.
                 */
                for (String element : classPathLibs) {
                    if ( ! libraries.contains(element)) {
                        it.add(element);
                        if (isFine) {
                            elementsAdded.append(element).append(" ");
                        }
                    }
                }
                if (elementsAdded != null) {
                    if (elementsAdded.length() > 0) {
                        logger.fine("Added following entries from " + 
                            entry + " Class-Path to client JAR classpath: [ " + elementsAdded.toString() + "]");
                    } else {
                        logger.fine("No Class-Path entries to add to client JAR classpath from manifest of " + entry);
                    }
                }
            }
        }
    
private static voidaddJARClassPathElementsFromDirectory(java.io.File directory, java.io.File archiveRoot, java.util.Collection classPathEntries)
Adds entries to the collection of class path elements for each JAR in the specified directory. The entries are paths relative to the archive root.

param
directory the directory to search for JARs
param
archiveRoot the root directory of the archive in which the directory resides
param
classPathEntries a Collection to which class path entries are added

        // Make sure the directory exists and is a directory.  For example, the 
        // default library-directory might not be present, or the developer might
        // have specified a non-existent directory for the library directory or
        // in the Class-Path entry of a JAR's manifest.
        boolean isFine = logger.isLoggable(Level.FINE);
        StringBuilder jarsAdded = null;
        URI relativeDirURI = null;
        String relativeDirURIPath = null;
        if (isFine) {
            jarsAdded = new StringBuilder();
            relativeDirURI = archiveRoot.toURI().relativize(directory.toURI());
            // If the directory and the archive root are the same, the relatived
            // path is an empty string.  In that case use a "." instead for
            // clarity in the log messages.
            
            if (directory.equals(archiveRoot)) {
                relativeDirURIPath = ".";
            } else {
                relativeDirURIPath = relativeDirURI.getPath();
            }
        }

        if (directory.exists() && directory.isDirectory()) {
            for (File candidateJAR : directory.listFiles()) {
                // Include only JARs.  Make sure it is not a directory, because
                // directories can be arbitrarily named and can end with .jar.
                if (candidateJAR.getName().endsWith(".jar") && ! candidateJAR.isDirectory()) {
                    URI jarRelativeURI = archiveRoot.toURI().relativize(candidateJAR.toURI());
                    classPathEntries.add(jarRelativeURI.getPath());
                    if (isFine) {
                        jarsAdded.append(relativeDirURI.relativize(jarRelativeURI)).append(" ");
                    }
                }
            }
        }
        if (isFine) {
            logger.fine("Adding these JARs from directory " + 
                relativeDirURIPath + " to app client JAR classpath: [" + jarsAdded.toString() + "]");
        }
    
static voidcopy(com.sun.enterprise.deployment.deploy.shared.AbstractArchive source, com.sun.enterprise.deployment.deploy.shared.AbstractArchive target, java.lang.String entryName)
copy the entryName element from the source abstract archive into the target abstract archive

            
        InputStream is=null;
        OutputStream os=null;
        try {
            is = source.getEntry(entryName);
            if (is != null) {
                try {
                    os = target.putNextEntry(entryName);
                } catch(ZipException ze) {
                    // this is a duplicate...
                    return;
                }
                ArchivistUtils.copyWithoutClose(is, os);
            } else {
                // This may be a directory specification if there is no entry
                // in the source for it...for example, a directory expression
                // in the Class-Path entry from a JAR's manifest.  
                // 
                // Try to copy all entries from the source that have the 
                // entryName as a prefix.
                for (Enumeration e = source.entries(entryName); e.hasMoreElements();) {
                    copy(source, target, (String) e.nextElement());
                }
            }
        } catch (IOException ioe) {
            throw ioe;
        } finally {
            IOException closeEntryIOException = null;
            if (os!=null) {
                try {
                    target.closeEntry();
                } catch (IOException ioe) { 
                    closeEntryIOException = ioe;
                }
            }
            if (is!=null) {
                is.close();
            }
 
            if (closeEntryIOException != null) {
                throw closeEntryIOException;
            } 
        }
    
private static voidcopyArchive(com.sun.enterprise.deployment.deploy.shared.AbstractArchive source, com.sun.enterprise.deployment.deploy.shared.AbstractArchive target, java.util.Set excludeList)

        for (Enumeration e = source.entries();e.hasMoreElements();) {
            String entryName = String.class.cast(e.nextElement());
            if (excludeList.contains(entryName)) {
                continue;
            }
            try {
                copy(source, target, entryName);
            } catch(IOException ioe) {
                // duplicate, we ignore
            }
        }
    
static voidcopyDeploymentDescriptors(com.sun.enterprise.deployment.archivist.Archivist archivist, com.sun.enterprise.deployment.deploy.shared.AbstractArchive original, com.sun.enterprise.deployment.deploy.shared.AbstractArchive generated, com.sun.enterprise.deployment.deploy.shared.AbstractArchive target)


        AbstractArchive source = (generated == null) ? original : generated;
        //standard dd
        copy(source, target, 
             archivist.getStandardDDFile().getDeploymentDescriptorPath());
        //runtime dd
        copy(source, target, 
             archivist.getConfigurationDDFile().getDeploymentDescriptorPath());
    
static voidcopyLibraries(com.sun.enterprise.deployment.deploy.shared.AbstractArchive source, com.sun.enterprise.deployment.deploy.shared.AbstractArchive target, java.util.List libraries)

        for (String library : libraries) {
            copy(source, target, library);
        }
    
private static java.util.ListgetClassPathElementsFromManifest(java.util.jar.Manifest mf, java.net.URI appURI, java.net.URI referencingURI)
Returns a list of URIs (relative to the application) for the class path entries (if any) from the specified manifest.

param
mf the Manifest to be inspected
param
referencingURI the URI (relative to the application's top-level) of module or JAR containing the manifest
return
List containing URIs in string form for the libraries needed by this manifest's Class-Path

        ArrayList<String> classPathLibs = new ArrayList<String>();
        if (mf == null) {
            return classPathLibs;
        }
        
        Attributes mainAttrs = mf.getMainAttributes();
        if (mainAttrs == null) {
            return classPathLibs;
        }
        
        String classPathString = mainAttrs.getValue(Attributes.Name.CLASS_PATH);
        if (classPathString == null || classPathString.length() == 0) {
            return classPathLibs;
        }
        
        for (String classPathElement : classPathString.split(" ")) {
            URI elementURI = appURI.relativize(referencingURI.resolve(classPathElement));
            classPathLibs.add(elementURI.toString());
        }
        
        return classPathLibs;
    
static java.util.ListgetLibraryEntries(com.sun.enterprise.deployment.Application app, com.sun.enterprise.deployment.deploy.shared.AbstractArchive appSource)
This method finds all the library entries - JARs and directories - needed by the appclient. Do not optimize by gathering all non-submodule JARs in the archive because that (1) ignores directories in JAR Class-Path entries and (2) may gather JARs that should be excluded.


        boolean isFine = logger.isLoggable(Level.FINE);
        
        File appArchive = new File(appSource.getArchiveUri());
    
        Vector<String> libraries = new Vector();
        
        // Process any JARs in the <library-directory>.
        String libraryDirectoryPath = app.getLibraryDirectory();
        File libraryDirectory = null;
        if (libraryDirectoryPath != null) {
            libraryDirectory = new File(appArchive, libraryDirectoryPath);
            addJARClassPathElementsFromDirectory(libraryDirectory, appArchive, libraries);
        }
        
        // For backward compatibility process any JARs at the top level of the 
        // archive, unless that is also the <library-directory> which we don't
        // want to process twice.
        if (libraryDirectory == null || ! libraryDirectory.equals(appArchive)) {
            addJARClassPathElementsFromDirectory(appArchive, appArchive, libraries);
        }
        
        if (DeploymentLogger.get().isLoggable(Level.FINEST)) {
            for (String lib : libraries) {
                DeploymentLogger.get().fine(
                    "Adding to the appclient jar, library [" + lib + "]");
            }
        }
        return libraries;
    
static java.net.URIgetParent(java.net.URI uri)
Returns a URI representing the parent of the specified URI.

param
uri the URI whose parent is needed
return
the URI of the parent; could be the empty string

        return getParent(uri.toString());
    
static java.net.URIgetParent(java.lang.String uriString)
Returns a URI representing the parent of the specified URI.

param
uriString the URI whose parent is needed
return
the URI of the parent; could be the empty string

        int endOfParentURI = uriString.lastIndexOf("/") + 1;
        String parentURIString = endOfParentURI != 0 ? uriString.substring(0, endOfParentURI) : "";
        URI parentURI = new URI(parentURIString);
        return parentURI;
    
static voidpopulateModuleJar(com.sun.enterprise.deployment.deploy.shared.AbstractArchive original, com.sun.enterprise.deployment.deploy.shared.AbstractArchive generated, com.sun.enterprise.deployment.deploy.shared.AbstractArchive target)
Populates a module archive using the contents of the original and generated archives.

Intended for use in building a top-level module archive.

param
original the AbstractArchive containing the input
param
generated the AbstractArchive for the generated bits for this application
param
target the archive to be created

        /*
         * Record library JARs and directories that must be included in the
         * app client archive.
         */
        ArrayList<String> libraries = new ArrayList<String>();
        
        /*
         * Class-Path entries in this module's manifest will be relative to
         * the module's parent.
         */
        File appArchive = new File(original.getArchiveUri());
        URI uri = appArchive.toURI();
        URI parentURI = null;
        try {
            parentURI = getParent(uri);
        } catch (URISyntaxException ex) {
            IOException ioe = new IOException();
            ioe.initCause(ex);
            throw ioe;
        }
        populateModuleJar(original, generated, target, libraries, parentURI, parentURI);
        
        // Go through the JARs to be added to the classpath.  For each one check
        // to see if it has a Manifest Class-Path entry.  If so, add each
        // part of the Class-Path entry to the list of libraries.  Note that the
        // entries can be either JARs or directories.  Either will work.
        addClassPathElementsFromManifestClassPaths(appArchive, libraries);

        /*
         * Copy any libraries we need.
         */
        copyLibraries(original, target, libraries);
    
static voidpopulateModuleJar(com.sun.enterprise.deployment.deploy.shared.AbstractArchive original, com.sun.enterprise.deployment.deploy.shared.AbstractArchive generated, com.sun.enterprise.deployment.deploy.shared.AbstractArchive target, java.util.List libraries, java.net.URI containingAppURI, java.net.URI moduleParentURI)
Populates a module archive.

Typically intended for use in processing a submodule contained withint a parent archive.

param
original the AbstractArchive containing the input
param
generated the AbstractArchive for the generated bits for this application
param
target the archive to be created
param
libraries List of Strings (possibly added to) refering to JARs or directories to be included in the generated app client JAR


        // Exclude the client jar file we are trying to generate
        String excludeFileName = target.getArchiveUri().substring(
            target.getArchiveUri().lastIndexOf(File.separatorChar)+1);
        Set excludeList = new HashSet();
        excludeList.add(excludeFileName); 

        // Copy all the generated content first.  Note that this
        // needs to be done before copying the original content
        // as any duplicates are otherwise ignored.
        // Also the ClientJarMaker does not have special knowledge
        // on what's modified.  that burden is on the deployment process to
        // make sure all generated content are available in the generated/xml
        if (generated != null) {
            copyArchive(generated, target, excludeList);
        }

        // preserve all entries in the original appclient jar
        copyArchive(original, target, excludeList);

        // copy manifest file since it does not appear in the list of files
        copy(original, target, JarFile.MANIFEST_NAME);
        
        // Add the manifest Class-Path entries (if any) from the submodule's
        // archive to the accumulated library list
        Manifest mf = original.getManifest();
        addClassPathElementsFromManifest(mf, containingAppURI, moduleParentURI, libraries);
    
static voidpopulateStubs(com.sun.enterprise.deployment.deploy.shared.AbstractArchive target, com.sun.enterprise.util.zip.ZipItem[] stubs)


          
          
        Set elements = new HashSet();
        for (ZipItem item : stubs) {
            if (elements.contains(item.getName())) {
                continue;
            }
            elements.add(item.getName());
            OutputStream os = null;
            InputStream is = null;
            try {
                os = target.putNextEntry(item.getName());
                is = new BufferedInputStream(new FileInputStream(item.getFile()));
                ArchivistUtils.copyWithoutClose(is, os);
            } finally {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    target.closeEntry();
                }
            }
        }