FileDocCategorySizeDatePackage
NestedAppClientInfo.javaAPI DocGlassfish v2 API17366Mon Jul 16 13:12:00 BST 2007com.sun.enterprise.appclient

NestedAppClientInfo

public class NestedAppClientInfo extends AppClientInfo
Represents an app client that is nested inside an enterprise app. Note that this could be either an undeployed ear that contains one or more embedded app clients or the generated jar file from the back-end that intentionally resembles an application archive because of other files that had to be packaged with the app client.
author
tjquinn

Fields Summary
private com.sun.enterprise.deployment.Application
appDesc
private com.sun.enterprise.deployment.ApplicationClientDescriptor
selectedAppClientDescriptor
which of possibly several app clients in the app the user chose
private String
displayNameFromCommandLine
display name specified (if any) on the command line to use in selecting the desired client main class
Constructors Summary
public NestedAppClientInfo(boolean isJWS, Logger logger, File archive, com.sun.enterprise.deployment.archivist.Archivist archivist, String mainClassFromCommandLine, String displayNameFromCommandLine)

    
     
                  
                
              
        super(isJWS, logger, archive, archivist, mainClassFromCommandLine);
        this.displayNameFromCommandLine = displayNameFromCommandLine;
    
Methods Summary
private com.sun.enterprise.deployment.ApplicationClientDescriptorchooseFromEmbeddedAppClients(java.util.Set embeddedAppClients, java.lang.String mainClassFromCommandLine, java.lang.String displayNameFromCommandLine)

        ApplicationClientDescriptor result = null;
        
        /*
         *There are at least two app clients embedded in the ear.
         *
         *To remain compatible with earlier releases the logic below
         *exits the loop immediately upon finding a matching app client
         *using the user-provided main class name.  If there are other
         *app clients with the same main class those are ignored.
         *
         *On the other hand, if the user specified the target display name 
         *then the logic below makes sure that exactly one app client
         *has that display name.  
         *
         */
        for (ApplicationClientDescriptor candidate : embeddedAppClients) {
           /*
            *If the user specified a main class name, use that value to
            *match against the candiate.
            */
           if (mainClassFromCommandLine != null) {
               if (candidate.getMainClassName().equals(mainClassFromCommandLine)) {
                   result = candidate;
                   /*
                    *Because the main class name is used as the criteria,
                    *exit the loop as soon as one matching app client if found.
                    */
                   break;
               }
           } else {
               /*
                *We know at this point that the user provided a display name.
                */
               if (candidate.getName().equals(displayNameFromCommandLine)) {
                   /*
                    *Make sure no other candidate already matched the
                    *target display name.
                    */
                   if (result == null) {
                       result = candidate;
                       /*
                        *Because the display name is used as the matching
                        *criteria, continue the loop to make sure there are
                        *not multiple app clients with the same display name
                        */
                   } else {
                       throw new IllegalArgumentException(localStrings.getString("appclient.duplicate_display_name", displayNameFromCommandLine));
                   }
               }
           }
        }
        return result;
    
protected com.sun.enterprise.deployment.deploy.shared.AbstractArchiveexpand(java.io.File file)
Expands the contents of the source archive into a temporary directory, using the same format as backend server expansions.

param
file an archive file to be expanded
return
an opened FileArchive for the expanded directory archive
exception
IOException in case of errors during the expansion


        File tmpDir = createTmpArchiveDir(file);
        _logger.fine("Expanding original archive " + file.getAbsolutePath() + 
                " into " + tmpDir.getAbsolutePath());

        // first explode the top level jar
        J2EEModuleExploder.explodeJar(file, tmpDir);

        // now we need to load the application standard deployment descriptor.
        FileArchive appArchive = new FileArchive();
        appArchive.open(tmpDir.getAbsolutePath());

        ApplicationArchivist archivist = new ApplicationArchivist();
        if (archivist.hasStandardDeploymentDescriptor(appArchive)) {
            appDesc = (Application) 
            archivist.readStandardDeploymentDescriptor(appArchive);
        } else {
            appDesc = Application.createApplication(appArchive,true);
        }
        
        // explode the sub modules, skipping the ones that do not exist since
        // the generated appclient jar files do not contain web content
        Iterator<ModuleDescriptor> bundles = appDesc.getModules();
        while (bundles.hasNext()) {

            ModuleDescriptor bundle = bundles.next();
            
            String moduleName = bundle.getArchiveUri();
            File srcArchive = new File(tmpDir, moduleName);

            if (srcArchive.exists()) {
                String massagedModuleName =  
                    FileUtils.makeFriendlyFilename(moduleName);
                File moduleDir = 
                    new File(tmpDir, massagedModuleName);
                J2EEModuleExploder.explodeJar(srcArchive, moduleDir);
            
                // delete the original module file
                srcArchive.delete();
            }
        }

        /*
         *Leave the new archive open so the caller can use it directly.
         */
        return appArchive;
    
protected com.sun.enterprise.deployment.ApplicationClientDescriptorgetAppClient(com.sun.enterprise.deployment.archivist.Archivist archivist)
Reports which app client embedded in the application archive is the one the user has selected using either the main class or display name arguments from the command line.

return
the app client descriptor for the user-selected app client


        if (selectedAppClientDescriptor != null) {
            return selectedAppClientDescriptor;
        }

        Application app = Application.class.cast(archivist.getDescriptor());

        /*
         *There could be one or more app clients embedded in the enterprise app
         *in the archive.  Choose which one to run based on the user's 
         *command-line input.
         */
        Set<ApplicationClientDescriptor> embeddedAppClients = 
            (Set<ApplicationClientDescriptor>) 
                app.getApplicationClientDescriptors();

        /*
         *Make sure the application module contains at least one app client.
         */
        if (embeddedAppClients.size() == 0) {
            throw new IllegalArgumentException(
                localStrings.getString("appclient.noEmbeddedAppClients"));
        }

        /*
         *If there is exactly one app client in the ear, then that's the app
         *client to use.
         */
        if (embeddedAppClients.size() == 1) {
            selectedAppClientDescriptor = useFirstEmbeddedAppClient(
                    embeddedAppClients, mainClassFromCommandLine);
        } else {
            selectedAppClientDescriptor = chooseFromEmbeddedAppClients(
                    embeddedAppClients, mainClassFromCommandLine, 
                    displayNameFromCommandLine);

            /*
             *Make sure that we've selected an app client.
             */
            if (selectedAppClientDescriptor == null) {
                if (mainClassFromCommandLine != null) {
                    throw new IllegalArgumentException(localStrings.getString("appclient.noMatchingClientUsingMainClass", mainClassFromCommandLine));
                } else {
                    throw new IllegalArgumentException(localStrings.getString("appclient.noMatchingClientUsingDisplayName", displayNameFromCommandLine));
                }
            }
        }
        return selectedAppClientDescriptor;
    
protected java.lang.StringgetAppClientRoot(com.sun.enterprise.deployment.deploy.shared.AbstractArchive archive, com.sun.enterprise.deployment.ApplicationClientDescriptor descriptor)

        String appRoot = archive.getArchiveUri();
        String moduleUri = descriptor.getModuleDescriptor().getArchiveUri();
        String moduleRoot = appRoot + File.separator +
                    FileUtils.makeFriendlyFilename(moduleUri);
        return moduleRoot;
    
protected java.util.ListgetClassPaths(com.sun.enterprise.deployment.deploy.shared.AbstractArchive archive)
Construct the classpaths. The classpaths constructed here is slightly different from the backend. It does not process any web module. The paths included are: 1. all the module root directory (since expansion is needed) 2. all the .jar files found in the archive


        List<String> paths = new ArrayList();
        String appRoot = archive.getArchiveUri(); 
        paths.add(appRoot);

        if (appDesc != null) {
            //add all module roots
            Iterator<ModuleDescriptor> bundles = appDesc.getModules();
            while (bundles.hasNext()) {
                ModuleDescriptor bundle = bundles.next();
                String moduleRoot = appRoot + File.separator +
                    FileUtils.makeFriendlyFilename(bundle.getArchiveUri());
                paths.add(moduleRoot);
                
                // Because the app client submodule - like any submodule - is
                // expanded into a directory, the normal manifest processing
                // done for JARs will not be applied to it when this directory is added to
                // the class path of the EJBClassLoader.  So we need to explicitly
                // add the Class-Path elements from the manifest to the class path now.
                File manifestFile = new File(moduleRoot, JarFile.MANIFEST_NAME);
                if ( ! manifestFile.exists()) {
                    continue;
                }
                Manifest mf = null;
                InputStream manifestIS = null;
                try {
                    manifestIS = new FileInputStream(manifestFile);
                    mf = new Manifest(manifestIS);
                    Attributes mainAttrs = mf.getMainAttributes();
                    if (mainAttrs != null) {
                        String classPathString = mainAttrs.getValue(Attributes.Name.CLASS_PATH);
                        if (classPathString != null) {
                            URI appRootURI = new File(appRoot).toURI();
                            String bundleURIString = bundle.getArchiveUri();
                            int lastSlash = bundleURIString.lastIndexOf("/");
                            String parentURIString;
                            if (lastSlash >=0) {
                                parentURIString = bundleURIString.substring(0, lastSlash);
                            } else {
                                parentURIString = "";
                            }
                            String parentDirPath = new File(appRootURI.resolve(parentURIString)).getAbsolutePath();
                            for (String classPathElement : classPathString.split(" ")) {
                                paths.add(parentDirPath + File.separator + classPathElement.replace("/",File.separator));
                            }
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(localStrings.getString("appclient.cannotOpenModuleManifest", bundle.getArchiveUri()), e);
                } finally {
                    if (manifestIS != null) {
                        try {
                            manifestIS.close();
                        } catch (IOException ioe) {
                            throw new RuntimeException(localStrings.getString("appclient.cannotCloseModuleManifest", bundle.getArchiveUri()), ioe);
                        }
                    }
                }
            }
        } else {
            //@@@ read it from the archive
            //shouldn't ever be here though since the appDesc should have been
            //initialized when expand() is called.
        }

        //add all jar files
        for (Enumeration en = archive.entries(); en.hasMoreElements(); ) {
            String entryName = (String) en.nextElement();
            if (entryName.endsWith(".jar")) {
                String entry = appRoot + File.separator + entryName;
                paths.add(entry);
            }
        }

        return paths;
    
private com.sun.enterprise.deployment.ApplicationClientDescriptoruseFirstEmbeddedAppClient(java.util.Set embeddedAppClients, java.lang.String mainClassNameFromCommandLine)

        ApplicationClientDescriptor result = null;
        
        /*
         *If the size is 1 then there is sure to be a non-null .next.
         *Still, may as well be sure.
         */
        Iterator<ApplicationClientDescriptor> it = embeddedAppClients.iterator();
        if ( ! it.hasNext()) {
            throw new IllegalStateException(localStrings.getString("appclient.unexpectedEndOfEmbeddedClients"));
        }

        result = embeddedAppClients.iterator().next();

        /*
         *If, in addition, the user specified a main class on the command
         *line, then use the user's class name as the main class name, rather
         *than the class specified by the Main-Class attribute in the
         *app client archive.  This allows the user to override the Main-Class
         *setting in the app client's manifest.
         */
        if (mainClassNameFromCommandLine != null) {
            result.setMainClassName(mainClassNameFromCommandLine);
        }
        return result;