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

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

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2012 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.deploy.shared.ArchiveFactory;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.archivist.AppClientArchivist;
import com.sun.enterprise.deployment.archivist.Archivist;
import com.sun.enterprise.deployment.archivist.ArchivistFactory;
import com.sun.enterprise.deployment.util.DOLUtils;
import org.glassfish.api.deployment.archive.ArchiveType;
import org.glassfish.deployment.common.ModuleDescriptor;

import com.sun.enterprise.universal.i18n.LocalStringsImpl;
import java.io.IOException;
import java.net.URI;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.deployment.common.RootDeploymentDescriptor;
import org.glassfish.hk2.api.ServiceLocator;
import org.xml.sax.SAXParseException;

import javax.enterprise.deploy.shared.ModuleType;

/**
 *
 * @author tjquinn
 */
public class UndeployedLaunchable implements Launchable {

    private static final LocalStringsImpl localStrings = new LocalStringsImpl(UndeployedLaunchable.class);

    private final String callerSuppliedMainClassName;

    private ApplicationClientDescriptor acDesc = null;

    private AppClientArchivist archivist = null;

    private final ReadableArchive clientRA;

    private ClassLoader classLoader = null;

    static UndeployedLaunchable newUndeployedLaunchable(
            final ServiceLocator habitat,
            final ReadableArchive ra,
            final String callerSuppliedMainClassName,
            final String callerSuppliedAppName,
            final ClassLoader classLoader) throws IOException, SAXParseException, UserError {

        ArchivistFactory af = Util.getArchivistFactory();

        /*
         * Try letting the factory decide what type of archive this is.  That
         * will often allow an app client or an EAR archive to be detected
         * automatically.
         */
        Archivist archivist = af.getArchivist(ModuleType.CAR.toString(), classLoader);
        if (archivist == null) {
            throw new UserError(localStrings.get("appclient.invalidArchive",
                    ra.getURI().toASCIIString()));
        }

        final ArchiveType moduleType = archivist.getModuleType();
        if (moduleType != null && moduleType.equals(DOLUtils.carType())) {
            return new UndeployedLaunchable(habitat, ra,
                    (AppClientArchivist) archivist, callerSuppliedMainClassName);
        } else if (moduleType != null && moduleType.equals(DOLUtils.earType())) {
            /*
             * Locate the app client submodule that matches the main class name
             * or the app client name.
             */

            Application app = (Application) archivist.open(ra);
            for (ModuleDescriptor md : app.getModules()) {
                if ( ! md.getModuleType().equals(DOLUtils.carType())) {
                    continue;
                }

                ApplicationClientDescriptor acd = (ApplicationClientDescriptor) md.getDescriptor();

                final String displayName = acd.getDisplayName();
                final String appName = acd.getModuleID();

                ArchiveFactory archiveFactory = Util.getArchiveFactory();
                ReadableArchive clientRA = archiveFactory.openArchive(ra.getURI().resolve(md.getArchiveUri()));

                /*
                 * Choose this nested app client if the caller-supplied name
                 * matches, or if the caller-supplied main class matches, or
                 * if neither was provided.  
                 */
                final boolean useThisClient =
                        (displayName != null && displayName.equals(callerSuppliedAppName))
                     || (appName != null && appName.equals(callerSuppliedAppName))
                     || (callerSuppliedMainClassName != null && clientRA.exists(classToResource(callerSuppliedMainClassName))
                     || (callerSuppliedAppName == null && callerSuppliedMainClassName == null));

                if (useThisClient) {
                    return new UndeployedLaunchable(habitat, clientRA, acd,
                            callerSuppliedMainClassName);
                }
                clientRA.close();
            }

            throw new UserError(localStrings.get("appclient.noMatchingClientInEAR",
                    ra.getURI(), callerSuppliedMainClassName, callerSuppliedAppName));
        } else {
            /*
             * There is a possibility that the user is trying to launch an
             * archive that is more than one type of archive: such as an EJB
             * but also an app client (because the manifest identifies a main
             * class, for example).
             *
             * Earlier the archivist factory might have returned the other type
             * of archivist - such as the EJB archivist.  Now see if the app
             * client archivist will work when selected directly.
             */
            archivist = af.getArchivist(DOLUtils.carType());

            /*
             * Try to open the archive as an app client archive just to see
             * if it works.
             */
            RootDeploymentDescriptor tempACD = archivist.open(ra);
            if (tempACD != null && tempACD instanceof ApplicationClientDescriptor) {
                /*
                 * Start with a fresh archivist - unopened - so we can request
                 * anno processing, etc. before opening it for real.
                 */
                archivist = af.getArchivist(DOLUtils.carType());
                return new UndeployedLaunchable(habitat, ra, (AppClientArchivist) archivist,
                                callerSuppliedMainClassName);
            }
            throw new UserError(
                    localStrings.get("appclient.unexpectedArchive", ra.getURI()));
        }
    }

    public URI getURI() {
        return clientRA.getURI();
    }

    public String getAnchorDir() {
        return null;
    }

    private static String classToResource(final String className) {
        return className.replace('.', '/') + ".class";
    }

    private UndeployedLaunchable(final ServiceLocator habitat,
            final ReadableArchive clientRA,
            final String callerSuppliedMainClass) throws IOException, SAXParseException {
        this.callerSuppliedMainClassName = callerSuppliedMainClass;
        this.clientRA = clientRA;
    }
    private UndeployedLaunchable(final ServiceLocator habitat,
            final ReadableArchive clientRA,
            final ApplicationClientDescriptor acd,
            final String callerSuppliedMainClass) throws IOException, SAXParseException {
        this(habitat, clientRA, callerSuppliedMainClass);
        this.acDesc = acd;
    }

    private UndeployedLaunchable(final ServiceLocator habitat,
            final ReadableArchive clientRA,
            final AppClientArchivist archivist,
            final String callerSuppliedMainClass) throws IOException, SAXParseException {
        this(habitat, clientRA, callerSuppliedMainClass);
        this.archivist = completeInit(archivist);
    }

    public Class getMainClass() throws ClassNotFoundException {
        try {
            String mainClassName = mainClassNameToLaunch();
            return Class.forName(mainClassName, true, getClassLoader());
        } catch (Exception e) {
            throw new ClassNotFoundException("");
        }
    }

    private ClassLoader getClassLoader() {
        if (classLoader == null) {
            classLoader = Thread.currentThread().getContextClassLoader();
        }
        return classLoader;
    }

    private String mainClassNameToLaunch() throws IOException, SAXParseException {
        return (callerSuppliedMainClassName != null ? callerSuppliedMainClassName :
            extractMainClassFromArchive(clientRA));
    }

    private String extractMainClassFromArchive(final ReadableArchive clientRA) throws IOException  {
        final Manifest mf = clientRA.getManifest();
        if (mf == null) {
            return null;
        }
        return mf.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
    }

    public ApplicationClientDescriptor getDescriptor(final URLClassLoader loader) throws IOException, SAXParseException {
        this.classLoader = loader;
        if (acDesc == null) {
            final AppClientArchivist _archivist = getArchivist(
                    AccessController.doPrivileged(new PrivilegedAction() {

                        @Override
                        public ACCClassLoader run() {
                            return new ACCClassLoader(loader.getURLs(), loader.getParent());
                        }
                    }));
                    
            _archivist.setAnnotationProcessingRequested(true);
            acDesc = _archivist.open(clientRA);
            
            Application.createVirtualApplication(null, acDesc.getModuleDescriptor());
            acDesc.getApplication().setAppName(getDefaultApplicationName(clientRA));
        }
        return acDesc;
    }

    public String getDefaultApplicationName(ReadableArchive archive) {
        String appName = archive.getName();
        int lastDot = appName.lastIndexOf('.');
        if (lastDot != -1) {
            if (appName.substring(lastDot).equalsIgnoreCase(".ear") ||
                appName.substring(lastDot).equalsIgnoreCase(".jar")) {
                appName = appName.substring(0, lastDot);
            }
        }
        return appName;
    }

    private AppClientArchivist completeInit(final AppClientArchivist arch) {
            arch.setDescriptor(acDesc);
            arch.setAnnotationProcessingRequested(true);
            return arch;
    }

    private AppClientArchivist getArchivist(final ClassLoader classLoader) throws IOException {
        if (archivist == null) {
            ArchivistFactory af = Util.getArchivistFactory();

            archivist = completeInit((AppClientArchivist) af.getArchivist(ModuleType.CAR.toString()));
        }
        archivist.setClassLoader(classLoader);
        return archivist;
    }

    public void validateDescriptor() {
        try {
            getArchivist(classLoader).validate(classLoader);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy