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

org.glassfish.javaee.full.deployment.EarDeployer Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 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.javaee.full.deployment;

import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.BundleDescriptor;
import org.glassfish.api.ActionReport.ExitCode;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.ApplicationContainer;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.Deployer;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.MetaData;
import org.glassfish.api.deployment.OpsParams;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.deployment.archive.ArchiveHandler;
import org.glassfish.api.container.Container;
import org.glassfish.api.ActionReport;
import org.glassfish.api.event.Events;
import org.glassfish.api.container.Sniffer;
import org.glassfish.deployment.common.DeploymentContextImpl;
import org.glassfish.deployment.common.DeploymentException;
import org.glassfish.deployment.common.DummyApplication;
import org.glassfish.deployment.common.RootDeploymentDescriptor;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.EngineInfo;
import org.glassfish.internal.data.ModuleInfo;
import org.glassfish.internal.data.ProgressTracker;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.internal.deployment.ExtendedDeploymentContext;
import org.jvnet.hk2.annotations.Service;
import jakarta.inject.Inject;

import org.glassfish.hk2.api.PerLookup;
import com.sun.enterprise.deployment.util.DOLUtils;
import org.glassfish.deployment.common.ModuleDescriptor;
import org.glassfish.api.deployment.archive.ArchiveType;
import com.sun.enterprise.deploy.shared.ArchiveFactory;
import com.sun.enterprise.deployment.deploy.shared.Util;
import com.sun.enterprise.util.LocalStringManagerImpl;

import java.util.Collection;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.IOException;
import java.io.File;

import org.glassfish.logging.annotation.LogMessageInfo;
import org.glassfish.logging.annotation.LoggerInfo;
import org.glassfish.logging.annotation.LogMessagesResourceBundle;

/**
 * EarDeployer to deploy composite Java EE applications.
 * todo : could be generified into any composite applications.
 *
 * @author Jerome Dochez
 */
@Service
@PerLookup
public class EarDeployer implements Deployer {

    //    private static final Class GLASSFISH_APPCLIENT_GROUP_FACADE_CLASS =
//            org.glassfish.appclient.client.AppClientGroupFacade.class;
// Currently using a string instead of a Class constant to avoid a circular
// dependency.  
    @Inject
    Deployment deployment;

    @Inject
    ServerEnvironment env;

    @Inject
    ArchiveFactory archiveFactory;

    @Inject
    Events events;

    @LogMessagesResourceBundle
    private static final String SHARED_LOGMESSAGE_RESOURCE = "org.glassfish.deployment.LogMessages";

    // Reserve this range [AS-DEPLOYMENT-02001, AS-DEPLOYMENT-04000]
    // for message ids used in this deployment javaee-full module
    @LoggerInfo(subsystem = "DEPLOYMENT", description = "Deployment logger for javaee-full module", publish = true)
    private static final String DEPLOYMENT_LOGGER = "javax.enterprise.system.tools.deployment.javaeefull";

    public static final Logger deplLogger =
        Logger.getLogger(DEPLOYMENT_LOGGER, SHARED_LOGMESSAGE_RESOURCE);

    @LogMessageInfo(message = "Skipped processing for module {0} as its module type was not recognized", level = "WARNING")
    private static final String UNRECOGNIZED_MODULE_TYPE = "AS-DEPLOYMENT-02015";

    @LogMessageInfo(message = "Error occurred", level = "WARNING")
    private static final String ERROR_OCCURRED = "AS-DEPLOYMENT-02016";

    final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(EarDeployer.class);

    public MetaData getMetaData() {
        return new MetaData(false, null, new Class[]{Application.class});
    }

    public Object loadMetaData(Class type, DeploymentContext context) {
        return null;
    }

    public boolean prepare(final DeploymentContext context) {

        final Application application = context.getModuleMetaData(Application.class);

        DeployCommandParameters deployParams = context.getCommandParameters(DeployCommandParameters.class);
        final String appName = deployParams.name();

        final CompositeApplicationInfo appInfo =
            new CompositeApplicationInfo(events, application, context.getSource(), appName, archiveFactory, env);
        for (Object m : context.getModuleMetadata()) {
            appInfo.addMetaData(m);
        }

        try {
            doOnAllBundles(application, (BundleBlock) bundle -> {
                ExtendedDeploymentContext sContext = appInfo.subContext(application, context, bundle.getArchiveUri());
                ModuleInfo info = prepareBundle(bundle, application, sContext);
                if (info == null) {
                    sContext.getActionReport().setActionExitCode(ExitCode.WARNING);
                    String msg = localStrings.getLocalString("skipmoduleprocessing", "Skipped processing for module {0} as its module type was not recognized", bundle.getArchiveUri());
                    sContext.getActionReport().setMessage(msg);
                    deplLogger.log(Level.WARNING,
                        UNRECOGNIZED_MODULE_TYPE,
                        bundle.getArchiveUri());
                    return null;
                }
                info.addMetaData(application);
                BundleDescriptor bundleDesc = application.getModuleByUri(
                    bundle.getArchiveUri());
                info.addMetaData(bundleDesc);
                for (RootDeploymentDescriptor ext :
                    bundleDesc.getExtensionsDescriptors()) {
                    info.addMetaData(ext);
                }
                appInfo.addModule(info);
                return info;
            });
        } catch (DeploymentException dde) {
            throw dde;
        } catch (Exception e) {
            DeploymentException de = new DeploymentException(e.getMessage());
            de.initCause(e);
            throw de;
        }

        context.getSource().removeExtraData(Hashtable.class);
        context.addModuleMetaData(appInfo);
        generateArtifacts(context);
        return true;
    }

    protected void generateArtifacts(final DeploymentContext context) throws DeploymentException {
        /*
         * The EAR-level app client artifact - the app client group facade -
         * is generated the first time an app client facade is generated.  At
         * that time all other deployers have run so any client artifacts
         * they create will be available and can be packaged into the group
         * facade.
         */
    }


    /**
     * Performs the same runnable task on each specified bundle.
     *
     * @param bundles  the bundles on which to perform the task
     * @param runnable the task to perform
     * @throws Exception
     */
    private void doOnBundles(
        final Collection> bundles,
        final BundleBlock runnable) throws Exception {
        for (ModuleDescriptor module : bundles) {
            runnable.doBundle(module);
        }
    }

    private Collection> doOnAllTypedBundles(
        Application application,
        ArchiveType type,
        BundleBlock runnable
    )
        throws Exception {

        final Collection> typedBundles = application.getModuleDescriptorsByType(type);
        doOnBundles(typedBundles, runnable);
        return typedBundles;
    }

    private void doOnAllBundles(Application application, BundleBlock runnable) throws Exception {

        Collection bundles =
            new LinkedHashSet();
        bundles.addAll(application.getModules());

        // if the initialize-in-order flag is set
        // we load the modules by their declaration order in application.xml
        if (application.isInitializeInOrder()) {
            for (final ModuleDescriptor bundle : bundles) {
                runnable.doBundle(bundle);
            }
        }

        // otherwise we load modules by default order: connector, ejb, web and
        // saving app client for last (because other submodules might generated
        // artifacts that should be included in the generated app client JAR
        else {
            // first we take care of the connectors
            bundles.removeAll(doOnAllTypedBundles(application, DOLUtils.rarType(), runnable));

            // now the EJBs
            bundles.removeAll(doOnAllTypedBundles(application, DOLUtils.ejbType(), runnable));

            // finally the war files.
            bundles.removeAll(doOnAllTypedBundles(application, DOLUtils.warType(), runnable));

            // extract the app client bundles to take care of later
            Collection> appClientBundles =
                application.getModuleDescriptorsByType(DOLUtils.carType());
            bundles.removeAll(appClientBundles);

            // now ther remaining bundles
            for (final ModuleDescriptor bundle : bundles) {
                runnable.doBundle(bundle);
            }

            // Last, deal with the app client bundles
            doOnBundles(appClientBundles, runnable);
        }
    }

    private ModuleInfo prepareBundle(final ModuleDescriptor md, Application application, final ExtendedDeploymentContext bundleContext)
        throws Exception {

        List orderedContainers;

        ProgressTracker tracker = bundleContext.getTransientAppMetaData(ExtendedDeploymentContext.TRACKER, ProgressTracker.class);

        try {
            // let's get the previously stored list of sniffers
            Hashtable> sniffersTable = bundleContext.getSource().getParentArchive().getExtraData(Hashtable.class);
            Collection sniffers = sniffersTable.get(md.getArchiveUri());
            // let's get the list of containers interested in this module
            orderedContainers = deployment.setupContainerInfos(null, sniffers, bundleContext);
            if (orderedContainers == null) {
                return null;
            }
        } catch (Exception e) {
            deplLogger.log(Level.WARNING,
                ERROR_OCCURRED,
                e);
            throw e;
        }
        return deployment.prepareModule(orderedContainers, md.getArchiveUri(), bundleContext, tracker);
    }

    public ApplicationContainer load(Container container, DeploymentContext context) {

        return new DummyApplication();
    }

    public void unload(ApplicationContainer appContainer, DeploymentContext context) {
        // nothing to do
    }

    public void clean(DeploymentContext context) {
        // nothing to do
    }

    private interface BundleBlock {

        T doBundle(ModuleDescriptor bundle) throws Exception;
    }

    private static Properties getModuleProps(DeploymentContext context, String moduleUri) {
        Map modulePropsMap = context.getModulePropsMap();
        Properties moduleProps = modulePropsMap.get(moduleUri);
        if (moduleProps == null) {
            moduleProps = new Properties();
            modulePropsMap.put(moduleUri, moduleProps);
        }
        return moduleProps;
    }

    private static class CompositeApplicationInfo extends ApplicationInfo {

        private final Application application;
        private ArchiveFactory archiveFactory;
        private ServerEnvironment env;

        private CompositeApplicationInfo(
            final Events events,
            final Application application,
            final ReadableArchive source,
            final String name,
            final ArchiveFactory archiveFactory,
            final ServerEnvironment env
        ) {
            super(events, source, name);
            this.application = application;
            this.archiveFactory = archiveFactory;
            this.env = env;
        }

        @Override
        protected ExtendedDeploymentContext getSubContext(ModuleInfo module, ExtendedDeploymentContext context) {
            return subContext(application, context, module.getName());
        }

        private ExtendedDeploymentContext subContext(final Application application, final DeploymentContext context, final String moduleUri) {

            ExtendedDeploymentContext moduleContext = ((ExtendedDeploymentContext) context).getModuleDeploymentContexts().get(moduleUri);
            if (moduleContext != null) {
                return moduleContext;
            }


            final ReadableArchive subArchive;
            try {
                subArchive = context.getSource().getSubArchive(moduleUri);
                subArchive.setParentArchive(context.getSource());
            } catch (IOException ioe) {
                deplLogger.log(Level.WARNING,
                    ERROR_OCCURRED,
                    ioe);
                return null;
            }

            ActionReport subReport =
                context.getActionReport().addSubActionsReport();
            moduleContext = new EarDeployerDeploymentContextImpl(subReport, context, moduleUri, subArchive, env, archiveFactory, application);

            ((ExtendedDeploymentContext) context).getModuleDeploymentContexts().put(moduleUri, moduleContext);
            moduleContext.setParentContext((ExtendedDeploymentContext) context);
            moduleContext.setModuleUri(moduleUri);
            ArchiveHandler subHandler = context.getModuleArchiveHandlers().get(moduleUri);
            moduleContext.setArchiveHandler(subHandler);

            return moduleContext;
        }
    }

    private static class EarDeployerDeploymentContextImpl extends DeploymentContextImpl {
        private final DeploymentContext context;
        private final String moduleUri;
        private final ReadableArchive subArchive;
        private final ArchiveFactory archiveFactory;
        private final Application application;

        public EarDeployerDeploymentContextImpl(
            final ActionReport subReport,
            final DeploymentContext context,
            final String moduleUri,
            final ReadableArchive subArchive,
            final ServerEnvironment env,
            final ArchiveFactory archiveFactory,
            final Application application
        ) {
            super(subReport, context.getSource(), context.getCommandParameters(OpsParams.class), env);
            this.context = context;
            this.moduleUri = moduleUri;
            this.subArchive = subArchive;
            this.archiveFactory = archiveFactory;
            this.application = application;
        }


        @Override
        public ClassLoader getClassLoader() {
            try {
                if (context.getClassLoader() == null) {
                    return null;
                }
                EarClassLoader appCl = EarClassLoader.class.cast(context.getClassLoader());
                if (((ExtendedDeploymentContext) context).getPhase() == Phase.PREPARE) {
                    return appCl;
                } else {
                    return appCl.getModuleClassLoader(moduleUri);
                }
            } catch (ClassCastException e) {
                return context.getClassLoader();
            }
        }

        @Override
        public ClassLoader getFinalClassLoader() {
            try {
                EarClassLoader finalEarCL = (EarClassLoader) context.getFinalClassLoader();
                return finalEarCL.getModuleClassLoader(moduleUri);
            } catch (ClassCastException e) {
                return context.getClassLoader();
            }
        }

        @Override
        public ReadableArchive getSource() {
            return subArchive;
        }

        @Override
        public Properties getAppProps() {
            return context.getAppProps();
        }

        @Override
        public  U getCommandParameters(Class commandParametersType) {
            return context.getCommandParameters(commandParametersType);
        }

        @Override
        public void addTransientAppMetaData(String metaDataKey,
                                            Object metaData) {
            context.addTransientAppMetaData(metaDataKey,
                metaData);
        }

        @Override
        public  T getTransientAppMetaData(String metaDataKey,
                                             Class metadataType) {
            return context.getTransientAppMetaData(metaDataKey,
                metadataType);
        }

        @Override
        public Properties getModuleProps() {
            return EarDeployer.getModuleProps(context, moduleUri);
        }

        @Override
        public ReadableArchive getOriginalSource() {
            try {
                File appRoot = context.getSourceDir();
                File origModuleFile = new File(appRoot, moduleUri);
                return archiveFactory.openArchive(
                    origModuleFile);
            } catch (IOException ioe) {
                return null;
            }
        }

        @Override
        public File getScratchDir(String subDirName) {
            String modulePortion = Util.getURIName(
                getSource().getURI());
            return (new File(super.getScratchDir(subDirName),
                modulePortion));
        }

        @Override
        public  T getModuleMetaData(Class metadataType) {
            try {
                return metadataType.cast(application.getModuleByUri(moduleUri));
            } catch (Exception e) {
                // let's first try the extensions mechanisms...
                if (RootDeploymentDescriptor.class.isAssignableFrom(metadataType)) {
                    for (RootDeploymentDescriptor extension : application.getModuleByUri(moduleUri).getExtensionsDescriptors((Class) metadataType)) {
                        // we assume there can only be one type of
                        if (extension != null) {
                            try {
                                return metadataType.cast(extension);
                            } catch (Exception e1) {
                                // next one...
                            }
                        }
                    }

                }

                return context.getModuleMetaData(metadataType);
            }
        }
    }
}