All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.appclient.client.acc.NestedAppClientInfo Maven / Gradle / Ivy

There is a newer version: 6.2024.6
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.appclient.client.acc;

import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.archivist.Archivist;
import com.sun.enterprise.deployment.archivist.ApplicationArchivist;
import org.glassfish.deployment.common.ModuleDescriptor;
import com.sun.enterprise.util.io.FileUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Logger;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.deployment.common.ModuleExploder;

/**
 * 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
 */
public class NestedAppClientInfo extends AppClientInfo {

    /** which of possibly several app clients in the app the user chose */
    private ApplicationClientDescriptor selectedAppClientDescriptor = null;

    /** display name specified (if any) on the command line to use in selecting the desired client main class */
    private String displayNameFromCommandLine;
    
    public NestedAppClientInfo(
            boolean isJWS, Logger logger, File archive, 
            Archivist archivist, String mainClassFromCommandLine, 
            String displayNameFromCommandLine) {
//        super(isJWS, logger, archive, archivist, mainClassFromCommandLine);
        super(isJWS, logger, mainClassFromCommandLine);
        this.displayNameFromCommandLine = displayNameFromCommandLine;
    }

    /**
     *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
     */
    @Override
    protected ApplicationClientDescriptor getAppClient(Archivist archivist) {

        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 embeddedAppClients = 
            (Set) 
                app.getBundleDescriptors(ApplicationClientDescriptor.class);

        /*
         *Make sure the application module contains at least one app client.
         */
        if (embeddedAppClients.size() == 0) {
            throw new IllegalArgumentException(
                getLocalString(
                    "appclient.noEmbeddedAppClients",
                    "The specified application module does not contain any app clients"));
        }

        /*
         *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(getLocalString(
                            "appclient.noMatchingClientUsingMainClass",
                            "Could not locate an embedded app client matching the main class name {0}",
                            mainClassFromCommandLine));
                } else {
                    throw new IllegalArgumentException(getLocalString(
                            "appclient.noMatchingClientUsingDisplayName",
                            "Could not locate an embedded app client matching the display name {0}",
                            displayNameFromCommandLine));
                }
            }
        }
        return selectedAppClientDescriptor;
    }

    private ApplicationClientDescriptor chooseFromEmbeddedAppClients(
            Set embeddedAppClients, 
            String mainClassFromCommandLine, 
            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(getLocalString(
                               "appclient.duplicate_display_name",
                               "More than one nested app client was found with the display name {0}",
                               displayNameFromCommandLine));
                   }
               }
           }
        }
        return result;
    }
        
    private ApplicationClientDescriptor useFirstEmbeddedAppClient(Set embeddedAppClients, 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 it = embeddedAppClients.iterator();
        if ( ! it.hasNext()) {
            throw new IllegalStateException(getLocalString(
                    "appclient.unexpectedEndOfEmbeddedClients",
                    "The application module seems to contain one app client but the iterator reported no more elements prematurely"));
        }

        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;
    }

//    /**
//     *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
//     */
//    @Override
//    protected ReadableArchive expand(File file)
//        throws IOException, Exception {
//
//        File tmpDir = createTmpArchiveDir(file);
//        _logger.fine("Expanding original archive " + file.getAbsolutePath() +
//                " into " + tmpDir.getAbsolutePath());
//
//        // first explode the top level jar
//        ModuleExploder.explodeJar(file, tmpDir);
//
//        // now we need to load the application standard deployment descriptor.
//        ReadableArchive appArchive = archiveFactory.openArchive(tmpDir);
//
//        ApplicationArchivist archivist = new ApplicationArchivist();
//        if (archivist.hasStandardDeploymentDescriptor(appArchive)) {
//            appDesc = (Application)
//            archivist.readStandardDeploymentDescriptor(appArchive);
//        } else {
//            appDesc = Application.createApplication(habitat, null, new ApplicationClientDescriptor().getModuleDescriptor());
//        }
//
//        // explode the sub modules, skipping the ones that do not exist since
//        // the generated appclient jar files do not contain web content
//        for (ModuleDescriptor bundle : appDesc.getModules()) {
//
//            String moduleName = bundle.getArchiveUri();
//            File srcArchive = new File(tmpDir, moduleName);
//
//            if (srcArchive.exists()) {
//                String massagedModuleName =
//                    FileUtils.makeFriendlyFilename(moduleName);
//                File moduleDir =
//                    new File(tmpDir, massagedModuleName);
//                ModuleExploder.explodeJar(srcArchive, moduleDir);
//
//                // delete the original module file
//                srcArchive.delete();
//            }
//        }
//
//        /*
//         *Leave the new archive open so the caller can use it directly.
//         */
//        return appArchive;
//    }

    /**
     * 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
     */
    @Override
    protected List getClassPaths(ReadableArchive archive) {

        List paths = new ArrayList();
        String appRoot = archive.getURI().toASCIIString();
        paths.add(appRoot);

        //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;
    }

    @Override
    protected String getAppClientRoot(
        ReadableArchive archive, ApplicationClientDescriptor descriptor) {
        String appRoot = archive.getURI().toASCIIString();
        String moduleUri = descriptor.getModuleDescriptor().getArchiveUri();
        String moduleRoot = appRoot + File.separator +
                    FileUtils.makeFriendlyFilename(moduleUri);
        return moduleRoot;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy