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

com.sun.enterprise.v3.server.ApplicationLifecycle 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) 2008-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.
 */

// Portions Copyright 2016-2023 Payara Foundation and/or its affiliates.

package com.sun.enterprise.v3.server;

import fish.payara.deployment.transformer.api.JakartaNamespaceDeploymentTransformer;
import fish.payara.nucleus.hotdeploy.HotDeployService;
import fish.payara.nucleus.hotdeploy.ApplicationState;
import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.deploy.shared.ArchiveFactory;
import com.sun.enterprise.deploy.shared.FileArchive;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.util.io.FileUtils;
import fish.payara.enterprise.config.serverbeans.DeploymentGroup;
import fish.payara.nucleus.executorservice.PayaraExecutorService;
import org.glassfish.api.ActionReport;
import org.glassfish.api.admin.ParameterMap;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.admin.config.ApplicationName;
import org.glassfish.api.container.Container;
import org.glassfish.api.container.Sniffer;
import org.glassfish.api.deployment.ApplicationMetaDataProvider;
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.UndeployCommandParameters;
import org.glassfish.api.deployment.archive.ArchiveDetector;
import org.glassfish.api.deployment.archive.ArchiveHandler;
import org.glassfish.api.deployment.archive.CompositeHandler;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.deployment.archive.WritableArchive;
import org.glassfish.api.event.EventListener.Event;
import org.glassfish.api.event.Events;
import org.glassfish.api.virtualization.VirtualizationEnv;
import org.glassfish.common.util.admin.ParameterMapExtractor;
import org.glassfish.deployment.common.ApplicationConfigInfo;
import org.glassfish.deployment.common.ClientJarWriter;
import org.glassfish.deployment.common.DeploymentContextImpl;
import org.glassfish.deployment.common.DeploymentException;
import org.glassfish.deployment.common.DeploymentProperties;
import org.glassfish.deployment.common.DeploymentUtils;
import org.glassfish.deployment.monitor.DeploymentLifecycleProbeProvider;
import org.glassfish.deployment.versioning.VersioningSyntaxException;
import org.glassfish.deployment.versioning.VersioningUtils;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.PreDestroy;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.classmodel.reflect.Parser;
import org.glassfish.hk2.classmodel.reflect.ParsingContext;
import org.glassfish.hk2.classmodel.reflect.Types;
import org.glassfish.hk2.classmodel.reflect.util.CommonModelRegistry;
import org.glassfish.hk2.classmodel.reflect.util.ResourceLocator;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.data.ContainerRegistry;
import org.glassfish.internal.data.EngineInfo;
import org.glassfish.internal.data.EngineRef;
import org.glassfish.internal.data.ModuleInfo;
import org.glassfish.internal.data.ProgressTracker;
import org.glassfish.internal.deployment.ApplicationLifecycleInterceptor;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.internal.deployment.DeploymentTracing;
import org.glassfish.internal.deployment.ExtendedDeploymentContext;
import org.glassfish.internal.deployment.analysis.DeploymentSpan;
import org.glassfish.internal.deployment.analysis.SpanSequence;
import org.glassfish.internal.deployment.analysis.StructuredDeploymentTracing;
import org.glassfish.internal.deployment.analysis.TraceContext;
import org.glassfish.kernel.KernelLoggerInfo;
import org.glassfish.server.ServerEnvironmentImpl;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.config.ConfigBean;
import org.jvnet.hk2.config.ConfigBeanProxy;
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.Dom;
import org.jvnet.hk2.config.RetryableException;
import org.jvnet.hk2.config.SingleConfigCode;
import org.jvnet.hk2.config.Transaction;
import org.jvnet.hk2.config.TransactionFailure;
import org.jvnet.hk2.config.types.Property;

import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import java.beans.PropertyVetoException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Level;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import java.util.logging.Logger;
import static java.util.stream.Collectors.toMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import java.net.URISyntaxException;
import org.glassfish.hk2.classmodel.reflect.util.ParsingConfig;
import org.glassfish.hk2.utilities.BuilderHelper;

/**
 * Application Loader is providing useful methods to load applications
 *
 * @author Jerome Dochez, Sanjeeb Sahoo
 */
@Service
@Singleton
public class ApplicationLifecycle implements Deployment, PostConstruct {

    private static final String[] UPLOADED_GENERATED_DIRS = new String [] {"policy", "xml", "ejb", "jsp"};

    @Inject
    protected SnifferManagerImpl snifferManager;

    @Inject
    ServiceLocator habitat;

    @Inject
    ArchiveFactory archiveFactory;

    @Inject
    ContainerRegistry containerRegistry;

    @Inject
    public ApplicationRegistry appRegistry;

    @Inject
    protected Applications applications;

    @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
    Server server;

    @Inject
    protected Domain domain;

    @Inject
    ServerEnvironmentImpl env;

    @Inject @org.jvnet.hk2.annotations.Optional
    VirtualizationEnv virtEnv;

    @Inject
    Events events;

    @Inject
    ConfigSupport configSupport;

    @Inject
    CommonClassLoaderServiceImpl commonClassLoaderService;

    @Inject
    PayaraExecutorService executorService;

    @Inject
    private HotDeployService hotDeployService;

    protected Logger logger = KernelLoggerInfo.getLogger();
    final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationLifecycle.class);

    private final ThreadLocal> currentDeploymentContext //
        = new ThreadLocal>() {

            @Override
            protected Deque initialValue() {
            return new ArrayDeque<>(5);
        }
    };

    protected DeploymentLifecycleProbeProvider
        deploymentLifecycleProbeProvider = null;

    private Collection alcInterceptors = Collections.EMPTY_LIST;

    @Override
    public void postConstruct() {
        deploymentLifecycleProbeProvider = new DeploymentLifecycleProbeProvider();
        alcInterceptors = habitat.getAllServices(ApplicationLifecycleInterceptor.class);

        // initialize listening services before application startup
        habitat.getAllServices(BuilderHelper.createNameFilter("ManagedBeanManagerImpl"));
        habitat.getAllServices(BuilderHelper.createNameFilter("ResourceManager"));
        habitat.getAllServices(BuilderHelper.createNameFilter("ApplicationScopedResourcesManager"));
    }

    /**
     * Returns the ArchiveHandler for the passed archive abstraction or null
     * if there are none.
     *
     * @param archive the archive to find the handler for
     * @return the archive handler or null if not found.
     * @throws IOException when an error occur
     */
    @Override
    public ArchiveHandler getArchiveHandler(ReadableArchive archive) throws IOException {
        return getArchiveHandler(archive, null);
    }

    /**
     * Returns the ArchiveHandler for the passed archive abstraction or null
     * if there are none.
     *
     * @param archive the archive to find the handler for
     * @param type the type of the archive
     * @return the archive handler or null if not found.
     * @throws IOException when an error occur
     */
    @Override
    public ArchiveHandler getArchiveHandler(ReadableArchive archive, String type) throws IOException {
        if (type != null) {
            ArchiveDetector archiveDetector = habitat.getService(ArchiveDetector.class, type);
            if (archiveDetector != null) {
                return archiveDetector.getArchiveHandler();
            }
        }
        List detectors = new ArrayList<>(habitat.getAllServices(ArchiveDetector.class));
        Collections.sort(detectors, new Comparator() {
            // rank 2 is considered lower than rank 1, let's sort them in inceasing order
            @Override
            public int compare(ArchiveDetector o1, ArchiveDetector o2) {
                return o1.rank() - o2.rank();
            }
        });
        for (ArchiveDetector ad : detectors) {
            if (ad.handles(archive)) {
                return ad.getArchiveHandler();
            }
        }
        return null;
    }

    @Override
    public ApplicationDeployment prepare(Collection sniffers, final ExtendedDeploymentContext context) {
        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);

        DeploymentSpan eventSpan = tracing.startSpan(DeploymentTracing.AppStage.PROCESS_EVENTS, Deployment.DEPLOYMENT_START.type());
        events.send(new Event<>(Deployment.DEPLOYMENT_START, context), false);
        eventSpan.close();

        currentDeploymentContext.get().push(context);
        final ActionReport report = context.getActionReport();
        final DeployCommandParameters commandParams = context.getCommandParameters(DeployCommandParameters.class);
        final String appName = commandParams.name();
        ApplicationInfo appInfo;
        Optional appState = hotDeployService.getApplicationState(context);

        final ClassLoader currentCL = Thread.currentThread().getContextClassLoader();
        ProgressTracker tracker = new ProgressTracker() {
            @Override
            public void actOn(Logger logger) {
                //loaded is used instead of started to include more modules to
                //stop. In some modules, the setup and cleanup steps are not
                //fully symmetric, and to ensure thorough cleanup, we need to
                //call module.stop() for started modules, and modules that are
                //loaded but may not be started. Issue 18263
                for (EngineRef module : get("loaded", EngineRef.class)) {
                    try {
                        module.stop(context);
                    } catch (Exception e) {
                        // ignore
                    }
                }
                try {
                    PreDestroy.class.cast(context).preDestroy();
                } catch (Exception e) {
                    // ignore
                }
                for (EngineRef module : get("loaded", EngineRef.class)) {
                    try {
                        module.unload(context);
                    } catch (Exception e) {
                        // ignore
                    }
                }
                try {
                    ApplicationInfo appInfo = appRegistry.get(appName);
                    if (appInfo != null) {
                        // send the event to close necessary resources
                        events.send(new Event<>(Deployment.APPLICATION_DISABLED, appInfo));
                    }
                } catch (Exception e) {
                    // ignore
                }
                for (EngineRef module : get("prepared", EngineRef.class)) {
                    try {
                        module.clean(context);
                    } catch (Exception e) {
                        // ignore
                    }
                }
                // comment this out for now as the interceptor seems to use
                // a different hook to roll back failure
                // notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.REPLICATION, context);

                if (!commandParams.keepfailedstubs) {
                    try {
                        context.clean();
                    } catch (Exception e) {
                        // ignore
                    }
                }
                appRegistry.remove(appName);

            }
        };

        try (DeploymentSpan topSpan = tracing.startSpan(DeploymentTracing.AppStage.PREPARE);
             SpanSequence span = tracing.startSequence(DeploymentTracing.AppStage.PREPARE, "ArchiveMetadata")) {
            if (commandParams.origin == OpsParams.Origin.deploy
                    && appRegistry.get(appName) != null
                    && !commandParams.hotDeploy) {
                report.setMessage(localStrings.getLocalString("appnamenotunique", "Application name {0} is already in use. Please pick a different name.", appName));
                report.setActionExitCode(ActionReport.ExitCode.FAILURE);
                return null;
            }

            // if the virtualservers param is not defined, set it to all
            // defined virtual servers minus __asadmin on that target
            if (commandParams.virtualservers == null) {
                commandParams.virtualservers = DeploymentUtils.getVirtualServers(
                        commandParams.target, env, domain);
            }

            if (commandParams.enabled == null) {
                commandParams.enabled = Boolean.TRUE;
            }

            if (commandParams.altdd != null) {
                context.getSource().addArchiveMetaData(DeploymentProperties.ALT_DD, commandParams.altdd);
            }

            if (commandParams.runtimealtdd != null) {
                context.getSource().addArchiveMetaData(DeploymentProperties.RUNTIME_ALT_DD, commandParams.runtimealtdd);
            }

            context.addTransientAppMetaData(ExtendedDeploymentContext.TRACKER, tracker);
            context.setPhase(DeploymentContextImpl.Phase.PREPARE);

            span.start("ArchiveHandler");
            ArchiveHandler handler = context.getArchiveHandler();
            if (handler == null) {
                handler = getArchiveHandler(context.getSource(),
                        commandParams.type);
                context.setArchiveHandler(handler);
            }

            if (handler == null) {
                report.setMessage(localStrings.getLocalString("unknownarchivetype", "Archive type of {0} was not recognized", context.getSourceDir()));
                report.setActionExitCode(ActionReport.ExitCode.FAILURE);
                return null;
            }

            span.start(DeploymentTracing.AppStage.CLASS_SCANNING);

            Types types = null;
            if (handler.requiresAnnotationScanning(context.getSource())) {
                types = getDeployableTypes(context);
            }

            span.finish();

            transformApplication(context, types, tracing, span);

            // containers that are started are not stopped even if
            // the deployment fail, the main reason
            // is that some container do not support to be restarted.
            if (sniffers != null && logger.isLoggable(Level.FINE)) {
                for (Sniffer sniffer : sniffers) {
                    logger.log(FINE, "Before Sorting{0}", sniffer.getModuleType());
                }
            }

            span.start(DeploymentTracing.AppStage.PREPARE, "Sniffer");

            sniffers = getSniffers(handler, sniffers, context);
            final Collection selectedSniffers = sniffers;
            appState.ifPresent(s -> s.setSniffers(selectedSniffers));

            span.start(DeploymentTracing.AppStage.PREPARE, "ClassLoaderHierarchy");

            ClassLoaderHierarchy clh = habitat.getService(ClassLoaderHierarchy.class);

            span.start(DeploymentTracing.AppStage.PREPARE, "ClassLoader");

            context.createDeploymentClassLoader(clh, handler);

            events.send(new Event<>(Deployment.AFTER_DEPLOYMENT_CLASSLOADER_CREATION, context), false);

            Thread.currentThread().setContextClassLoader(context.getClassLoader());

            span.start(DeploymentTracing.AppStage.PREPARE, "Container");

            final List sortedEngineInfos;
            if (appState.map(ApplicationState::getEngineInfos).isPresent()) {
                sortedEngineInfos = appState.get().getEngineInfos();
                loadDeployers(
                        sortedEngineInfos.stream()
                                .collect(toMap(EngineInfo::getDeployer, Function.identity())),
                        context
                );
            } else {
                sortedEngineInfos = setupContainerInfos(handler, sniffers, context);
                appState.ifPresent(s -> s.setEngineInfos(sortedEngineInfos));
            }

            // a bit more is happening here, but I cannot quite describe it yet
            span.start(DeploymentTracing.AppStage.CREATE_CLASSLOADER);

            if (sortedEngineInfos.isEmpty()) {
                throw new DeploymentException(localStrings.getLocalString("unknowncontainertype",
                    "There is no installed container capable of handling this application {0}",
                    context.getSource().getName()));
            }
            if (logger.isLoggable(Level.FINE)) {
                for (EngineInfo info : sortedEngineInfos) {
                    logger.log(FINE, "After Sorting {0}", info.getSniffer().getModuleType());
                }
            }

            // create a temporary application info to hold metadata
            // so the metadata could be accessed at classloader
            // construction time through ApplicationInfo
            ApplicationInfo tempAppInfo = new ApplicationInfo(events,
                    context.getSource(), appName);
            for (Object m : context.getModuleMetadata()) {
                tempAppInfo.addMetaData(m);
            }
            tempAppInfo.setIsJavaEEApp(sortedEngineInfos);
            // set the flag on the archive to indicate whether it's
            // a JavaEE archive or not
            context.getSource().setExtraData(Boolean.class, tempAppInfo.isJavaEEApp());
            appRegistry.add(appName, tempAppInfo);

            try {
                notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.PREPARE, context);
            } catch (Throwable interceptorException) {
                report.failure(logger, "Exception while invoking the lifecycle interceptor", null);
                report.setFailureCause(interceptorException);
                logger.log(SEVERE, KernelLoggerInfo.lifecycleException, interceptorException);
                tracker.actOn(logger);
                return null;
            }

            events.send(new Event<>(Deployment.DEPLOYMENT_BEFORE_CLASSLOADER_CREATION, context), false);

            context.createApplicationClassLoader(clh, handler);
            tempAppInfo.setAppClassLoader(context.getFinalClassLoader());
            
            events.send(new Event<>(Deployment.AFTER_APPLICATION_CLASSLOADER_CREATION, context), false);

            // this is a first time deployment as opposed as load following an unload event,
            // we need to create the application info
            // todo : we should come up with a general Composite API solution
            final ModuleInfo moduleInfo;
            try (SpanSequence innerSpan = span.start(DeploymentTracing.AppStage.PREPARE, "Module")){
                if (appState.map(ApplicationState::getModuleInfo).isPresent()) {
                    moduleInfo = appState.get().getModuleInfo();
                    moduleInfo.reset();
                } else {
                    moduleInfo = prepareModule(sortedEngineInfos, appName, context, tracker);
                    appState.ifPresent(s -> s.setModuleInfo(moduleInfo));
                }
                // Now that the prepare phase is done, any artifacts
                // should be available.  Go ahead and create the
                // downloadable client JAR.  We want to do this now, or
                // at least before the load and start phases, because
                // (for example) the app client deployer start phase
                // needs to find all generated files when it runs.
                final ClientJarWriter cjw = new ClientJarWriter(context);
                cjw.run();
            } catch (Throwable prepareException) {
                report.failure(logger, "Exception while preparing the app", null);
                report.setFailureCause(prepareException);
                logger.log(SEVERE, KernelLoggerInfo.lifecycleException, prepareException);
                tracker.actOn(logger);
                return null;
            }

            span.start(DeploymentTracing.AppStage.PROCESS_EVENTS, Deployment.APPLICATION_PREPARED.type());

            // the deployer did not take care of populating the application info, this
            // is not a composite module.
            if (appState.map(ApplicationState::getApplicationInfo).isPresent()) {
                appInfo = appState.get().getApplicationInfo();
                appInfo.reset(context.getSource());
                for (Object metadata : context.getModuleMetadata()) {
                    moduleInfo.addMetaData(metadata);
                    appInfo.addMetaData(metadata);
                }
            } else if ((appInfo = context.getModuleMetaData(ApplicationInfo.class)) == null) {
                ApplicationInfo applicationInfo = new ApplicationInfo(events, context.getSource(), appName);
                appInfo = applicationInfo;
                appInfo.addModule(moduleInfo);
                appState.ifPresent(s -> s.setApplicationInfo(applicationInfo));
                for (Object metadata : context.getModuleMetadata()) {
                    moduleInfo.addMetaData(metadata);
                    appInfo.addMetaData(metadata);
                }
            } else {
                for (EngineRef ref : moduleInfo.getEngineRefs()) {
                    appInfo.add(ref);
                }
            }

            // remove the temp application info from the registry
            // first, then register the real one
            appRegistry.remove(appName);
            appInfo.setIsJavaEEApp(sortedEngineInfos);
            appRegistry.add(appName, appInfo);

            notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.PREPARE, context);

            // send the APPLICATION_PREPARED event
            // set the phase and thread context classloader properly
            // before sending the event
            context.setPhase(DeploymentContextImpl.Phase.PREPARED);
            Thread.currentThread().setContextClassLoader(context.getClassLoader());
            appInfo.setAppClassLoader(context.getClassLoader());
            appState.ifPresent(s -> s.setApplicationClassLoader(context.getClassLoader()));
            events.send(new Event<>(Deployment.APPLICATION_PREPARED, context), false);

            if (loadOnCurrentInstance(context)) {
                appInfo.setLibraries(commandParams.libraries());
                try (SpanSequence innerSpan = span.start(DeploymentTracing.AppStage.LOAD)){
                    notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.LOAD, context);
                    appInfo.load(context, tracker);
                    notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.LOAD, context);
                } catch (Throwable loadException) {
                    logger.log(SEVERE, KernelLoggerInfo.lifecycleException, loadException);
                    report.failure(logger, "Exception while loading the app", null);
                    report.setFailureCause(loadException);
                    tracker.actOn(logger);
                    return null;
                }
            }
        } catch (DeploymentException de) {
            report.failure(logger, de.getMessage());
            tracker.actOn(logger);
            return null;
        } catch (Exception e) {
            report.failure(logger,
                localStrings.getLocalString("error.deploying.app", "Exception while deploying the app [{0}]", appName),
                null);
            report.setFailureCause(e);
            logger.log(SEVERE, KernelLoggerInfo.lifecycleException, e);
            tracker.actOn(logger);
            return null;
        } finally {
            Thread.currentThread().setContextClassLoader(currentCL);
            if (report.getActionExitCode() != ActionReport.ExitCode.SUCCESS) {
                context.postDeployClean(false /* not final clean-up yet */);
                events.send(new Event<>(Deployment.DEPLOYMENT_FAILURE, context));
            }
        }
        ApplicationDeployment depl = new ApplicationDeployment(appInfo, context);
        appRegistry.addTransient(depl);
        return depl;
    }

    @Override
    public void initialize(ApplicationInfo appInfo, Collection sniffers, ExtendedDeploymentContext context) {
        if(appInfo == null) {
            return;
        }
        appRegistry.removeTransient(appInfo.getName());
        final ActionReport report = context.getActionReport();
        ProgressTracker tracker = context.getTransientAppMetaData(ExtendedDeploymentContext.TRACKER, ProgressTracker.class);
        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);
        // now were falling back into the mainstream loading/starting sequence, at this
        // time the containers are set up, all the modules have been prepared in their
        // associated engines and the application info is created and registered
        if (loadOnCurrentInstance(context)) {
            try (SpanSequence span = tracing.startSequence(DeploymentTracing.AppStage.INITIALIZE)){
                notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.START, context);
                appInfo.initialize();
                appInfo.getModuleInfos().forEach(moduleInfo -> moduleInfo.getEngineRefs()
                        .forEach(engineRef -> tracker.add("initialized", EngineRef.class, engineRef)));
                span.start(DeploymentTracing.AppStage.START);
                appInfo.start(context, tracker);
                notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.START, context);
            } catch (Throwable loadException) {
                logger.log(SEVERE, KernelLoggerInfo.lifecycleException, loadException);
                report.failure(logger, "Exception while loading the app", null);
                report.setFailureCause(loadException);
                tracker.actOn(logger);
            } finally {
                context.postDeployClean(false /* not final clean-up yet */);
                if (report.getActionExitCode() == ActionReport.ExitCode.FAILURE) {
                    // warning status code is not a failure
                    events.send(new Event<>(Deployment.DEPLOYMENT_FAILURE, context));
                } else {
                    events.send(new Event<>(Deployment.DEPLOYMENT_SUCCESS, appInfo));
                }
            }
            currentDeploymentContext.get().pop();
        }
    }

    @Override
    public ApplicationInfo deploy(final ExtendedDeploymentContext context) {
        return deploy(null, context);
    }

    @Override
    public ApplicationInfo deploy(Collection sniffers, final ExtendedDeploymentContext context) {
        long operationStartTime = System.currentTimeMillis();
        ApplicationDeployment rv = prepare(sniffers, context);
        ApplicationInfo appInfo = rv != null? rv.appInfo : null;
        if (appInfo != null) {
            initialize(appInfo, sniffers, context);
            long operationTime = System.currentTimeMillis() - operationStartTime;
            deploymentLifecycleProbeProvider.applicationDeployedEvent( //
                appInfo.getName(), getApplicationType(appInfo), String.valueOf(operationTime));
        }
        return appInfo;
    }

    @Override
    @SuppressWarnings("squid:S2095")
    public Types getDeployableTypes(DeploymentContext context) throws IOException {
        synchronized (context) {
            Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class);
            if (types != null) {
                return types;
            }
            StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);
            Boolean skipScanExternalLibProp = Boolean.valueOf(context.getAppProps().getProperty(DeploymentProperties.SKIP_SCAN_EXTERNAL_LIB));

            Parser parser = getDeployableParser(context.getSource(), skipScanExternalLibProp, false, tracing,
                    context.getLogger(), context);
            ParsingContext parsingContext = parser.getContext();
            context.addTransientAppMetaData(Types.class.getName(), parsingContext.getTypes());
            context.addTransientAppMetaData(Parser.class.getName(), parser);
            return parsingContext.getTypes();
        }
    }

    public Parser getDeployableParser(ReadableArchive source, boolean skipScanExternalLibProp,
                                      boolean modelUnAnnotatedMembers, StructuredDeploymentTracing tracing,
                                      Logger logger, DeploymentContext deploymentContext) throws IOException {
        Parser parser = new Parser(createBuilder(modelUnAnnotatedMembers, logger).build());
        try(ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, source)) {
            DeploymentSpan mainScanSpan = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, source.getName());
            return processParsing(skipScanExternalLibProp, tracing, parser, scannerAdapter, mainScanSpan, deploymentContext);
        }
    }

    public Parser getDeployableParser(ReadableArchive source, boolean skipScanExternalLibProp,
                                      boolean modelUnAnnotatedMembers, StructuredDeploymentTracing tracing, Logger logger)
            throws java.io.IOException {
        Parser parser = new Parser(createBuilder(modelUnAnnotatedMembers, logger).build());
        ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, source);
        DeploymentSpan mainScanSpan = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, source.getName());
        return processParsing(source, skipScanExternalLibProp, tracing, parser, scannerAdapter, mainScanSpan);
    }

    public Parser processParsing(ReadableArchive source, boolean skipScanExternalLibProp,
                                 StructuredDeploymentTracing tracing, Parser parser,
                                 ReadableArchiveScannerAdapter scannerAdapter, DeploymentSpan mainScanSpan)
            throws IOException {
        try {
            parser.parse(scannerAdapter, () -> mainScanSpan.close());
            for (ReadableArchive externalLibArchive : getExternalLibraries(source, skipScanExternalLibProp)) {
                ReadableArchiveScannerAdapter libAdapter = null;
                try {
                    DeploymentSpan span = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, externalLibArchive.getName());
                    libAdapter = new ReadableArchiveScannerAdapter(parser, externalLibArchive);
                    parser.parse(libAdapter, () -> span.close());
                } finally {
                    if (libAdapter != null) {
                        libAdapter.close();
                    }
                }
            }
            parser.awaitTermination();
            scannerAdapter.close();
            return parser;
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }

    public Parser processParsing(boolean skipScanExternalLibProp,
                                 StructuredDeploymentTracing tracing, Parser parser,
                                 ReadableArchiveScannerAdapter scannerAdapter, DeploymentSpan mainScanSpan,
                                 DeploymentContext deploymentContext)
            throws IOException {
        try {
            parser.parse(scannerAdapter, () -> mainScanSpan.close());
            List externalLibraries = getExternalLibraries(skipScanExternalLibProp, deploymentContext);
            for (ReadableArchive externalLibArchive : externalLibraries) {
                DeploymentSpan span = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, externalLibArchive.getName());
                try (ReadableArchiveScannerAdapter libAdapter = new ReadableArchiveScannerAdapter(parser, externalLibArchive)) {
                    parser.parse(libAdapter, () -> span.close());
                }
            }
            parser.awaitTermination();
            for(ReadableArchive externalLibArchive: externalLibraries) {
                externalLibArchive.close();
            }
            return parser;
        } catch (InterruptedException | java.net.URISyntaxException e) {
            throw new IOException(e);
        }
    }

    public ParsingContext.Builder createBuilder(boolean modelUnAnnotatedMembers, Logger logger) {
        ResourceLocator locator = determineLocator();
        // scan the jar and store the result in the deployment context.
        ParsingContext.Builder parsingContextBuilder = new ParsingContext.Builder()
                .logger(logger)
                .executorService(executorService.getUnderlyingExecutorService())
                .config(new ParsingConfig() {
                    @Override
                    public Set getAnnotationsOfInterest() {
                        return Collections.emptySet();
                    }

                    @Override
                    public Set getTypesOfInterest() {
                        return Collections.emptySet();
                    }

                    @Override
                    public boolean modelUnAnnotatedMembers() {
                        return modelUnAnnotatedMembers;
                    }
                });
        // workaround bug in Builder
        parsingContextBuilder.locator(locator);
        return parsingContextBuilder;
    }



    private ResourceLocator determineLocator() {
        if (CommonModelRegistry.getInstance().canLoadResources()) {
            // common model registry will handle our external class dependencies
            return null;
        }
        return new ClassloaderResourceLocatorAdapter(commonClassLoaderService.getCommonClassLoader());
    }

    private void transformApplication(ExtendedDeploymentContext context, Types types,
            StructuredDeploymentTracing tracing, SpanSequence span) throws IOException {
        String transformNS = System.getProperty("fish.payara.deployment.transform.namespace");

        if (Boolean.parseBoolean(transformNS) || transformNS == null) {
            span.start(DeploymentTracing.AppStage.TRANSFORM_ARCHIVE);

            Optional jakartaNamespaceDeploymentTransformerOptional;
            try {
                jakartaNamespaceDeploymentTransformerOptional = ServiceLoader.load(
                        JakartaNamespaceDeploymentTransformer.class).findFirst();
            } catch (NoClassDefFoundError exception) {
                // ClassNotFoundException gets thrown if we've found a service but couldn't instantiate it
                logger.log(Level.WARNING,
                        "Caught exception trying to instantiate a deployment transformer, skipping...",
                        exception);
                span.finish();
                return;
            }

            if (!jakartaNamespaceDeploymentTransformerOptional.isPresent()) {
                logger.log(Level.INFO, "No deployment transformer implementation found.");
                span.finish();
                return;
            }

            JakartaNamespaceDeploymentTransformer jakartaNamespaceDeploymentTransformerService =
                    jakartaNamespaceDeploymentTransformerOptional.get();

            if (types == null) {
                types = getDeployableTypes(context);
            }

            if (!jakartaNamespaceDeploymentTransformerService.isJakartaEEApplication(types)) {
                context.getSource().close();

                // DeploymentException will be thrown here if this fails
                File output = jakartaNamespaceDeploymentTransformerService.transformApplication(context);

                context.getAppProps().setProperty(ServerTags.EMPTY_BEANS_XML_MODE_ALL_PROP, Boolean.TRUE.toString());
                context.setSource((FileArchive) archiveFactory.createArchive(output));

                // reset transient and module data of original deployed archive
                context.removeTransientAppMetaData(Types.class.getName());
                context.removeTransientAppMetaData(Parser.class.getName());
                context.resetModuleMetaData();
                tracing.register(context);

                // Rescan for the data we just removed
                getDeployableTypes(context);
            }
            span.finish();
        }
    }

    private void notifyLifecycleInterceptorsBefore(final ExtendedDeploymentContext.Phase phase,
            final ExtendedDeploymentContext dc) {
        for (ApplicationLifecycleInterceptor i : alcInterceptors) {
            i.before(phase, dc);
        }
    }

    private void notifyLifecycleInterceptorsAfter(final ExtendedDeploymentContext.Phase phase,
            final ExtendedDeploymentContext dc) {
        for (ApplicationLifecycleInterceptor i : alcInterceptors) {
            i.after(phase, dc);
        }
    }

    private List getExternalLibraries(ReadableArchive source, Boolean skipScanExternalLibProp) throws IOException {
        List externalLibArchives = new ArrayList<>();

        if (skipScanExternalLibProp) {
            // if we skip scanning external libraries, we should just
            // return an empty list here
            return Collections.emptyList();
        }

        List externalLibs = DeploymentUtils.getExternalLibraries(source);
        for (URI externalLib : externalLibs) {
            externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath())));
        }

        return externalLibArchives;
    }

    private List getExternalLibraries(Boolean skipScanExternalLibProp,
                                                       DeploymentContext deploymentContext)
            throws IOException, URISyntaxException {
        List externalLibArchives = new ArrayList<>();

        if (skipScanExternalLibProp) {
            // if we skip scanning external libraries, we should just
            // return an empty list here
            return Collections.emptyList();
        }

        for(URI externalLib : DeploymentUtils.getExternalLibraries(deploymentContext.getSource())) {
            externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath())));
        }

        for (URI externalLib : deploymentContext.getAppLibs()) {
            externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath())));
        }

        return externalLibArchives;
    }

    /**
     * Suspends this application.
     *
     * @param appName the registration application ID
     * @return true if suspending was successful, false otherwise.
     */
    public boolean suspend(String appName) {
        boolean isSuccess = true;

        ApplicationInfo appInfo = appRegistry.get(appName);
        if (appInfo != null) {
            isSuccess = appInfo.suspend(logger);
        }

        return isSuccess;
    }

    /**
     * Resumes this application.
     *
     * @param appName the registration application ID
     * @return true if resumption was successful, false otherwise.
     */
    public boolean resume(String appName) {
        boolean isSuccess = true;

        ApplicationInfo appInfo = appRegistry.get(appName);
        if (appInfo != null) {
            isSuccess = appInfo.resume(logger);
        }

        return isSuccess;
    }

    @Override
    public List setupContainerInfos(DeploymentContext context)
        throws Exception {
        return setupContainerInfos(context.getArchiveHandler(), getSniffers(context.getArchiveHandler(), null, context), context);
    }

    @Override
    public Collection getSniffers(final ArchiveHandler handler, Collection sniffers, DeploymentContext context) {
        if (handler == null) {
            return Collections.emptyList();
        }

        if (sniffers==null) {
            if (handler instanceof CompositeHandler) {
                ((CompositeHandler)handler).initCompositeMetaData(context);
                context.getAppProps().setProperty(ServerTags.IS_COMPOSITE, "true");
            }
            sniffers = snifferManager.getSniffers(context);
        }
        context.addTransientAppMetaData(DeploymentProperties.SNIFFERS, sniffers);
        snifferManager.validateSniffers(sniffers, context);

        return sniffers;
    }

    /** set up containers and prepare the sorted ModuleInfos
     * @param handler
     * @param sniffers
     * @param context
     * @return
     * @throws java.lang.Exception  */
    @Override
    public List setupContainerInfos(final ArchiveHandler handler,
            Collection sniffers, DeploymentContext context)
             throws Exception {

        final ActionReport report = context.getActionReport();

        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);

        Map containerInfosByDeployers = new LinkedHashMap<>();

        for (Sniffer sniffer : sniffers) {
            if (sniffer.getContainersNames() == null || sniffer.getContainersNames().length == 0) {
                report.failure(logger, "no container associated with application of type : " + sniffer.getModuleType(), null);
                throw new DeploymentException(localStrings.getLocalString("unknowncontainertype", "There is no installed container capable of handling this application {0}", context.getSource().getName()));
            }

            final String containerName = sniffer.getContainersNames()[0];

            EngineInfo engineInfo = startEngine(context, sniffer, containerName);

            Deployer deployer = startDeployer(context, containerName, engineInfo);

            containerInfosByDeployers.put(deployer, engineInfo);
        }

        // all containers that have recognized parts of the application being deployed
        // have now been successfully started. Start the deployment process.
        List sortedEngineInfos = new ArrayList<>();

        // ok everything is satisfied, just a matter of running things in order
        List orderedDeployers = loadDeployers(
                containerInfosByDeployers,
                context
        );

        // now load metadata from deployers.
        for (Deployer deployer : orderedDeployers) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(FINE, "Ordered Deployer {0}", deployer.getClass());
            }

            final MetaData metadata = deployer.getMetaData();
            EngineInfo engineInfo = containerInfosByDeployers.get(deployer);
            try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.CONTAINER, engineInfo.getSniffer().getModuleType(), DeploymentTracing.AppStage.PREPARE, "MetaData")) {
                if (metadata!=null) {
                    if (metadata.provides()==null || metadata.provides().length==0) {
                        deployer.loadMetaData(null, context);
                    } else {
                        for (Class provide : metadata.provides()) {
                            if (context.getModuleMetaData(provide)==null) {
                                context.addModuleMetaData(deployer.loadMetaData(provide, context));
                            } else {
                                deployer.loadMetaData(null, context);
                            }
                        }
                    }
                } else {
                    deployer.loadMetaData(null, context);
                }
            } catch(Exception e) {
                report.failure(logger, "Exception while invoking " + deployer.getClass() + " prepare method", e);
                throw e;
            }

            sortedEngineInfos.add(containerInfosByDeployers.get(deployer));
        }

        return sortedEngineInfos;
    }

    private Deployer startDeployer(DeploymentContext context, String containerName, EngineInfo engineInfo) throws Exception {
        final ActionReport report = context.getActionReport();
        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);

        try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.CONTAINER, engineInfo.getSniffer().getModuleType(), DeploymentTracing.AppStage.PREPARE, "Deployer"))
        {
            Deployer deployer = engineInfo.getDeployer();
            if (deployer == null) {
                if (!startContainers(Collections.singleton(engineInfo), logger, context)) {
                    final String msg = "Aborting, Failed to start container " + containerName;
                    report.failure(logger, msg, null);
                    throw new Exception(msg);
                }
                deployer = engineInfo.getDeployer();

                if (deployer == null) {
                    report.failure(logger, "Got a null deployer out of the " + engineInfo.getContainer().getClass() + " container, is it annotated with @Service ?");
                    throw new DeploymentException("Deployer not found for container " + containerName);
                }
            }
            return deployer;
        }
    }

    private EngineInfo startEngine(DeploymentContext context, Sniffer sniffer, String containerName) throws Exception {
        final ActionReport report = context.getActionReport();

        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);

        // start all the containers associated with sniffers.
        try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.CONTAINER, sniffer.getModuleType(), DeploymentTracing.AppStage.PREPARE)) {
            EngineInfo engineInfo = containerRegistry.getContainer(containerName);
            if (engineInfo == null) {
                // need to synchronize on the registry to not end up starting the same container from
                // different threads.
                Collection containersInfo = null;
                synchronized (containerRegistry) {
                    if (containerRegistry.getContainer(containerName) == null) {
                        DeploymentSpan innerSpan = tracing.startSpan(DeploymentTracing.AppStage.CONTAINER_START);

                        containersInfo = setupContainer(sniffer, logger, context);

                        innerSpan.close();

                        if (containersInfo == null || containersInfo.isEmpty()) {
                            String msg = "Cannot start container(s) associated to application of type : " + sniffer.getModuleType();
                            report.failure(logger, msg, null);
                            throw new Exception(msg);
                        }
                    }
                }

                // now start all containers, by now, they should be all setup...
                if (containersInfo != null && !startContainers(containersInfo, logger, context)) {
                    final String msg = "Aborting, Failed to start container " + containerName;
                    report.failure(logger, msg, null);
                    throw new Exception(msg);
                }
            }
            engineInfo = containerRegistry.getContainer(containerName);

            if (engineInfo == null) {
                final String msg = "Aborting, Failed to start container " + containerName;
                report.failure(logger, msg, null);
                throw new Exception(msg);
            }
            return engineInfo;
        }
    }

    public Map getTypeByProvider() {
        // in reality, there is single implementation of ApplicationMetadataProvider at this point.
        final Map typeByProvider = new HashMap<>();
        final List providers = habitat.getAllServices(ApplicationMetaDataProvider.class);
        for (ApplicationMetaDataProvider provider : providers) {
            if (provider.getMetaData() != null) {
                for (Class provided : provider.getMetaData().provides()) {
                    typeByProvider.put(provided, provider);
                }
            }
        }

        // check if everything is provided.
        for (ApplicationMetaDataProvider provider : providers) {
            if (provider.getMetaData() != null) {
                for (Class dependency : provider.getMetaData().requires()) {
                    if (!typeByProvider.containsKey(dependency)) {
                        // at this point, I only log problems, because it maybe that what I am deploying now
                        // will not require this application metadata.
                        logger.log(WARNING, KernelLoggerInfo.applicationMetaDataProvider,
                                new Object[]{provider, dependency});
                    }
                }
            }
        }
        return typeByProvider;
    }

    private Map getTypeByDeployer(Map containerInfosByDeployers) {
        Map typeByDeployer = new HashMap<>();
        for (Deployer deployer : containerInfosByDeployers.keySet()) {
            if (deployer.getMetaData() != null) {
                for (Class provided : deployer.getMetaData().provides()) {
                    typeByDeployer.put(provided, deployer);
                }
            }
        }
        return typeByDeployer;
    }

    private List loadDeployers(
            Map containerInfosByDeployers,
            DeploymentContext context) throws IOException {

        final ActionReport report = context.getActionReport();
        final Map typeByProvider = getTypeByProvider();
        final Map typeByDeployer = getTypeByDeployer(containerInfosByDeployers);
        final StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);

        for (Deployer deployer : containerInfosByDeployers.keySet()) {
            if (deployer.getMetaData() != null) {
                for (Class dependency : deployer.getMetaData().requires()) {
                    if (!typeByDeployer.containsKey(dependency) && !typeByProvider.containsKey(dependency)) {

                        Service s = deployer.getClass().getAnnotation(Service.class);
                        String serviceName;
                        if (s != null && s.name() != null && s.name().length() > 0) {
                            serviceName = s.name();
                        } else {
                            serviceName = deployer.getClass().getSimpleName();
                        }
                        report.failure(logger, serviceName + " deployer requires " + dependency + " but no other deployer provides it", null);
                        return null;
                    }
                }
            }
        }

        List orderedDeployers = new ArrayList<>();
        for (Map.Entry entry : containerInfosByDeployers.entrySet()) {
            Deployer deployer = entry.getKey();
            if (logger.isLoggable(Level.FINE)) {
                logger.log(FINE, "Keyed Deployer {0}", deployer.getClass());
            }
            DeploymentSpan span = tracing.startSpan(TraceContext.Level.CONTAINER, entry.getValue().getSniffer().getModuleType(), DeploymentTracing.AppStage.PREPARE);
            loadDeployer(orderedDeployers, deployer, typeByDeployer, typeByProvider, context);
            span.close();
        }
        return orderedDeployers;
    }

    private void loadDeployer(List results, Deployer deployer, Map typeByDeployer,  Map typeByProvider, DeploymentContext dc)
        throws IOException {

        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(dc);
        if (results.contains(deployer)) {
            return;
        }
        results.add(deployer);
        if (deployer.getMetaData()!=null) {
            for (Class required : deployer.getMetaData().requires()) {
                if (dc.getModuleMetaData(required)!=null) {
                    continue;
                }
                if (typeByDeployer.containsKey(required)) {
                    loadDeployer(results,typeByDeployer.get(required), typeByDeployer, typeByProvider, dc);
                } else {
                    ApplicationMetaDataProvider provider = typeByProvider.get(required);
                    if (provider==null) {
                        logger.log(SEVERE, KernelLoggerInfo.inconsistentLifecycleState, required);
                    } else {
                        LinkedList providers = new LinkedList<>();

                        addRecursively(providers, typeByProvider, provider);
                        for (ApplicationMetaDataProvider p : providers) {
                            // this actually loads all descriptors of the app.
                            try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.APPLICATION, null, DeploymentTracing.AppStage.LOAD, "DeploymentDescriptor")) {
                                dc.addModuleMetaData(p.load(dc));
                            }
                        }
                    }
                }
            }
        }
    }

    private void addRecursively(LinkedList results, Map providers, ApplicationMetaDataProvider provider) {

        results.addFirst(provider);
        for (Class type : provider.getMetaData().requires()) {
            if (providers.containsKey(type)) {
                addRecursively(results, providers, providers.get(type));
            }
        }

    }

    @Override
    public ModuleInfo prepareModule(
        List sortedEngineInfos, String moduleName,
        DeploymentContext context,
        ProgressTracker tracker) throws Exception {

        List addedEngines = new ArrayList<>();

        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);
        tracing.switchToContext(TraceContext.Level.MODULE, moduleName);

        for (EngineInfo engineInfo : sortedEngineInfos) {
            // get the deployer
            Deployer deployer = engineInfo.getDeployer();

            try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.CONTAINER, engineInfo.getSniffer().getModuleType(), DeploymentTracing.AppStage.PREPARE)){
                deployer.prepare(context);

                // construct an incomplete EngineRef which will be later
                // filled in at loading time
                EngineRef engineRef = new EngineRef(engineInfo, null);
                addedEngines.add(engineRef);
                tracker.add("prepared", EngineRef.class, engineRef);

                tracker.add(Deployer.class, deployer);
            } catch(Exception e) {
                final ActionReport report = context.getActionReport();
                report.failure(logger, "Exception while invoking " + deployer.getClass() + " prepare method", e);
                throw e;
            }
        }

        if (events!=null) {
            DeploymentSpan span = tracing.startSpan(TraceContext.Level.MODULE, moduleName, DeploymentTracing.AppStage.PROCESS_EVENTS, Deployment.MODULE_PREPARED.type());
            events.send(new Event<>(Deployment.MODULE_PREPARED, context), false);
            span.close();
        }

        // I need to create the application info here from the context, or something like this.
        // and return the application info from this method for automatic registration in the caller.

        // set isComposite property on module props so we know whether to persist
        // module level properties inside ModuleInfo
        String isComposite = context.getAppProps()
                .getProperty(ServerTags.IS_COMPOSITE);
        if (isComposite != null) {
            context.getModuleProps().setProperty(ServerTags.IS_COMPOSITE, isComposite);
        }

        ModuleInfo mi = new ModuleInfo(events, moduleName, addedEngines,
            context.getModuleProps());

        /*
         * Save the application config that is potentially attached to each
         * engine in the corresponding EngineRefs that have already created.
         *
         * Later, in registerAppInDomainXML, the appInfo is saved, which in
         * turn saves the moduleInfo children and their engineRef children.
         * Saving the engineRef assigns the application config to the Engine
         * which corresponds directly to the  element in the XML.
         * A long way to get this done.
         */

//        Application existingApp = applications.getModule(Application.class, moduleName);
//        if (existingApp != null) {
            ApplicationConfigInfo savedAppConfig = new ApplicationConfigInfo(context.getAppProps());
            for (EngineRef er : mi.getEngineRefs()) {
               ApplicationConfig c = savedAppConfig.get(mi.getName(),
                       er.getContainerInfo().getSniffer().getModuleType());
               if (c != null) {
                   er.setApplicationConfig(c);
               }
            }
//        }
        return mi;
    }

    protected Collection setupContainer(Sniffer sniffer, Logger logger, DeploymentContext context) {
        ActionReport report = context.getActionReport();
        ContainerStarter starter = habitat.getService(ContainerStarter.class);
        Collection containersInfo = starter.startContainer(sniffer);
        if (containersInfo == null || containersInfo.isEmpty()) {
            report.failure(logger, "Cannot start container(s) associated to application of type : " + sniffer.getModuleType(), null);
            return null;
        }
        return containersInfo;
    }

    protected boolean startContainers(Collection containersInfo, Logger logger, DeploymentContext context) {

    	ActionReport report = context.getActionReport();
        for (EngineInfo engineInfo : containersInfo) {
            Container container;
            try {
                container = engineInfo.getContainer();
            } catch (Exception e) {
                if (e instanceof MultiException) {
                    for (Throwable se : ((MultiException) e).getErrors()) {
                        logger.log(SEVERE, e.getMessage(), e);
                    }
                }
                logger.log(SEVERE, KernelLoggerInfo.cantStartContainer,
                        new Object[] {engineInfo.getSniffer().getModuleType(), e});
                return false;
            }

            Class deployerClass = container.getDeployer();
            Deployer deployer;
            try {
                    deployer = habitat.getService(deployerClass);
                    engineInfo.setDeployer(deployer);
            } catch (MultiException e) {
                report.failure(logger, "Cannot instantiate or inject "+deployerClass, e);
                engineInfo.stop(logger);
                return false;
            } catch (ClassCastException e) {
                engineInfo.stop(logger);
                report.failure(logger, deployerClass+" does not implement " +
                                    " the org.jvnet.glassfish.api.deployment.Deployer interface", e);
                return false;
            }
        }
        return true;
    }

    protected void stopContainers(EngineInfo[] ctrInfos, Logger logger) {
        for (EngineInfo ctrInfo : ctrInfos) {
            try {
                ctrInfo.stop(logger);
            } catch(Exception e) {
                // this is not a failure per se but we need to document it.
                logger.log(INFO, KernelLoggerInfo.cantReleaseContainer,
                        new Object[] {ctrInfo.getSniffer().getModuleType(), e});
            }
        }
    }

    @Override
    public ApplicationInfo unload(ApplicationInfo info, ExtendedDeploymentContext context) {
        ActionReport report = context.getActionReport();
        if (info==null) {
            report.failure(context.getLogger(), "Application not registered", null);
            return null;
        }

        notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.STOP, context);

        if (info.isLoaded()) {
            info.stop(context, context.getLogger());
            notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.STOP, context);

            notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.UNLOAD, context);
            info.unload(context);
            notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.UNLOAD, context);
        }

        events.send(new Event<>(Deployment.APPLICATION_DISABLED, info), false);

        try {
            notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.CLEAN, context);
            info.clean(context);
            notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.CLEAN, context);
        } catch(Exception e) {
            report.failure(context.getLogger(), "Exception while cleaning", e);
            return info;
        }

        return info;
    }

    @Override
    public void undeploy(String appName, ExtendedDeploymentContext context) {

        ActionReport report = context.getActionReport();
        UndeployCommandParameters params = context.getCommandParameters(UndeployCommandParameters.class);

        ApplicationInfo info = appRegistry.get(appName);
        if (info==null) {
            report.failure(context.getLogger(), "Application " + appName + " not registered", null);
            events.send(new Event(Deployment.UNDEPLOYMENT_FAILURE, context));
            return;

        }

        events.send(new Event(Deployment.UNDEPLOYMENT_START, info));

        // we unconditionally unload the application, even if it is not loaded, because we must clean the
        // application, especially the classloaders need to be closed to release file handles
        unload(info, context);


        if (report != null && report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
            events.send(new Event(Deployment.UNDEPLOYMENT_SUCCESS, context));
            deploymentLifecycleProbeProvider.applicationUndeployedEvent(appName, getApplicationType(info));
        } else {
            events.send(new Event(Deployment.UNDEPLOYMENT_FAILURE, context));
        }

        appRegistry.remove(appName);
    }

    // prepare application config change for later registering
    // in the domain.xml
    @Override
    public Transaction prepareAppConfigChanges(final DeploymentContext context)
        throws TransactionFailure {
        final Properties appProps = context.getAppProps();
        final DeployCommandParameters deployParams = context.getCommandParameters(DeployCommandParameters.class);
        Transaction tx = null;
        Application app_w= null;

        if (deployParams.hotDeploy) {
            app_w = applications.getApplication(deployParams.name);
        }
        if (app_w == null) {
            try {
                tx = new Transaction();
                // prepare the application element
                ConfigBean newBean = ((ConfigBean) Dom.unwrap(applications)).allocate(Application.class);
                Application app = newBean.createProxy();
                app_w = tx.enroll(app);
                setInitialAppAttributes(app_w, deployParams, appProps, context);
            } catch (TransactionFailure e) {
                tx.rollback();
                throw e;
            } catch (Exception e) {
                tx.rollback();
                throw new TransactionFailure(e.getMessage(), e);
            }
        }
        context.addTransientAppMetaData(ServerTags.APPLICATION, app_w);
        return tx;
    }

    // register application information in domain.xml
    @Override
    public void registerAppInDomainXML(final ApplicationInfo
        applicationInfo, final DeploymentContext context, Transaction t)
        throws TransactionFailure {
        registerAppInDomainXML(applicationInfo, context, t, false);
    }

    // register application information in domain.xml
    @Override
    public void registerAppInDomainXML(final ApplicationInfo
        applicationInfo, final DeploymentContext context, Transaction t,
        boolean appRefOnly)
        throws TransactionFailure {
        final Properties appProps = context.getAppProps();
        final DeployCommandParameters deployParams = context.getCommandParameters(DeployCommandParameters.class);
        if (t != null) {
            try {
                if (!appRefOnly) {
                    Application app_w = context.getTransientAppMetaData(
                        ServerTags.APPLICATION, Application.class);
                    // adding the application element
                    setRestAppAttributes(app_w, appProps);
                    Applications apps_w = t.enroll(applications);
                    apps_w.getModules().add(app_w);
                    if (applicationInfo != null) {
                        applicationInfo.save(app_w);
                    }
                }

                List targets = new ArrayList<>();
                if (!DeploymentUtils.isDomainTarget(deployParams.target)) {
                    targets.add(deployParams.target);
                } else {
                    List previousTargets = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_TARGETS, List.class);
		    if (previousTargets == null) {
                        previousTargets = domain.getAllReferencedTargetsForApplication(deployParams.name);
                    }
                    targets = previousTargets;
                }

                String origVS = deployParams.virtualservers;
                Boolean origEnabled = deployParams.enabled;
		Properties previousVirtualServers = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_VIRTUAL_SERVERS, Properties.class);
		Properties previousEnabledAttributes = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, Properties.class);
                for (String target : targets) {
                    // first reset the virtualservers, enabled attribute
                    deployParams.virtualservers = origVS;
                    deployParams.enabled = origEnabled;
                    // now if the target is domain target,
                    // restore the previous attributes if
                    // applicable
                    if (DeploymentUtils.isDomainTarget(deployParams.target)) {
                        String vs = previousVirtualServers.getProperty(target);
                        if (vs != null) {
                            deployParams.virtualservers = vs;
                        }
                        String enabledAttr = previousEnabledAttributes.getProperty(target);
                        if (enabledAttr != null) {
                            deployParams.enabled = Boolean.valueOf(enabledAttr);
                        }
                    }
                    if (deployParams.enabled == null) {
                        deployParams.enabled = Boolean.TRUE;
                    }
                    Server servr = domain.getServerNamed(target);
                    if (servr != null) {
                        ApplicationRef instanceApplicationRef = domain.getApplicationRefInTarget(deployParams.name, servr.getName());
                        if (instanceApplicationRef == null) {
                            // adding the application-ref element to the standalone
                            // server instance
                            ConfigBeanProxy servr_w = t.enroll(servr);
                            // adding the application-ref element to the standalone
                            // server instance
                            ApplicationRef appRef = servr_w.createChild(ApplicationRef.class);
                            setAppRefAttributes(appRef, deployParams);
                            ((Server) servr_w).getApplicationRef().add(appRef);
                        }
                    }

                    Cluster cluster = domain.getClusterNamed(target);
                    if (cluster != null) {
                        // adding the application-ref element to the cluster
                        // and instances
                        ConfigBeanProxy cluster_w = t.enroll(cluster);
                        ApplicationRef appRef = cluster_w.createChild(ApplicationRef.class);
                        setAppRefAttributes(appRef, deployParams);
                        ((Cluster)cluster_w).getApplicationRef().add(appRef);

                        for (Server svr : cluster.getInstances() ) {
                            ConfigBeanProxy svr_w = t.enroll(svr);
                            ApplicationRef appRef2 = svr_w.createChild(ApplicationRef.class);
                            setAppRefAttributes(appRef2, deployParams);
                            ((Server)svr_w).getApplicationRef().add(appRef2);
                        }
                    }

                    DeploymentGroup dg = domain.getDeploymentGroupNamed(target);
                    if (dg != null) {
                        ConfigBeanProxy dg_w = t.enroll(dg);
                        ApplicationRef appRef = dg_w.createChild(ApplicationRef.class);
                        setAppRefAttributes(appRef, deployParams);
                        ((DeploymentGroup)dg_w).getApplicationRef().add(appRef);
                        for (Server svr : dg.getInstances() ) {
                            ApplicationRef instanceApplicationRef = domain.getApplicationRefInTarget(deployParams.name, svr.getName());
                            if (instanceApplicationRef == null) {
                                ConfigBeanProxy svr_w = t.enroll(svr);
                                ApplicationRef appRef2 = svr_w.createChild(ApplicationRef.class);
                                setAppRefAttributes(appRef2, deployParams);
                                ((Server) svr_w).getApplicationRef().add(appRef2);
                            }
                        }
                    }
                }
            } catch(TransactionFailure e) {
                t.rollback();
                throw e;
            } catch (Exception e) {
                t.rollback();
                throw new TransactionFailure(e.getMessage(), e);
            }

            try {
                t.commit();
            } catch (RetryableException e) {
                System.out.println("Retryable...");
                // TODO : do something meaninful here
                t.rollback();
            } catch (TransactionFailure e) {
                t.rollback();
                throw e;
            }
        }
    }

    @Override
    public void registerTenantWithAppInDomainXML(
            final String appName,
            final ExtendedDeploymentContext context) throws TransactionFailure {

        final Transaction t = new Transaction();
        try {
            final AppTenant appTenant_w = writeableTenantForApp(
                    appName,
                    t);
            appTenant_w.setContextRoot(context.getAppProps().getProperty(ServerTags.CONTEXT_ROOT));
            appTenant_w.setTenant(context.getTenant());

            t.commit();
        } catch (TransactionFailure ex) {
            t.rollback();
            throw ex;
        } catch (Throwable ex) {
            t.rollback();
            throw new TransactionFailure(ex.getLocalizedMessage(), ex);
        }
    }

    @Override
    public void unregisterTenantWithAppInDomainXML(
            final String appName,
            final String tenantName
            ) throws TransactionFailure, RetryableException {
        final com.sun.enterprise.config.serverbeans.Application app =
                applications.getApplication(appName);
        if (app == null) {
            throw new IllegalArgumentException("Application " + appName + " not found");
        }
        final AppTenants appTenants = app.getAppTenants();
        final AppTenant appTenant = appTenants.getAppTenant(tenantName);
        if (appTenant == null) {
            throw new IllegalArgumentException("Tenant " + tenantName + " not provisioned for application " + appName);
        }
        Transaction t = new Transaction();
        final AppTenants appTenants_w = t.enroll(appTenants);
        appTenants_w.getAppTenant().remove(appTenant);
        t.commit();
    }

    private AppTenant writeableTenantForApp(
            final String appName,
            final Transaction t) throws TransactionFailure, PropertyVetoException {
        final com.sun.enterprise.config.serverbeans.Application app =
                applications.getApplication(appName);
        if (app == null) {
            throw new IllegalArgumentException("Application " + appName + " not found");
        }

        /*
         * The app-tenants subelement might or might not already be there.
         */
        AppTenants appTenants = app.getAppTenants();
        AppTenants appTenants_w;
        if (appTenants == null) {
            com.sun.enterprise.config.serverbeans.Application app_w =
                    t.enroll(app);
            appTenants_w = app_w.createChild(AppTenants.class);
            app_w.setAppTenants(appTenants_w);
        } else {
            appTenants_w = t.enroll(appTenants);
       }

        final List appTenantList = appTenants_w.getAppTenant();
        AppTenant appTenant_w = appTenants_w.createChild(AppTenant.class);
        appTenantList.add(appTenant_w);
        return appTenant_w;
    }

    // application attributes that are set in the beginning of the deployment
    // that will not be changed in the course of the deployment
    private void setInitialAppAttributes(Application app,
        DeployCommandParameters deployParams, Properties appProps,
        DeploymentContext context)
        throws PropertyVetoException {
        Properties previousEnabledAttributes = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, Properties.class);
        // various attributes
        app.setName(deployParams.name);
        if (deployParams.libraries != null) {
            app.setLibraries(deployParams.libraries);
        }
        if (deployParams.description != null) {
            app.setDescription(deployParams.description);
        }
        if (deployParams.deploymentorder != null) {
            app.setDeploymentOrder(deployParams.deploymentorder.toString());
        }

        app.setEnabled(String.valueOf(true));
        if (appProps.getProperty(ServerTags.LOCATION) != null) {
                    app.setLocation(appProps.getProperty(
                ServerTags.LOCATION));
            // when redeploy to domain we preserve the enable
            // attribute
            if (DeploymentUtils.isDomainTarget(deployParams.target)) {
                if (previousEnabledAttributes != null) {
                    String enabledAttr = previousEnabledAttributes.getProperty(DeploymentUtils.DOMAIN_TARGET_NAME);
                    if (enabledAttr != null) {
                        app.setEnabled(enabledAttr);
                    }
                }
            }
            app.setAvailabilityEnabled(deployParams.availabilityenabled.toString());
            app.setAsyncReplication(deployParams.asyncreplication.toString());
        }
        if (appProps.getProperty(ServerTags.OBJECT_TYPE) != null) {
            app.setObjectType(appProps.getProperty(
                ServerTags.OBJECT_TYPE));
        }
        if (appProps.getProperty(ServerTags.DIRECTORY_DEPLOYED)
            != null) {
            app.setDirectoryDeployed(appProps.getProperty(
                ServerTags.DIRECTORY_DEPLOYED));
        }
    }


    // set the rest of the application attributes at the end of the
    // deployment
    private void setRestAppAttributes(Application app, Properties appProps)
        throws PropertyVetoException, TransactionFailure {
        // context-root element
        if (appProps.getProperty(ServerTags.CONTEXT_ROOT) != null) {
            app.setContextRoot(appProps.getProperty(
                ServerTags.CONTEXT_ROOT));
        }
        // property element
        // trim the properties that have been written as attributes
        // the rest properties will be written as property element
        for (Object element : appProps.keySet()) {
        String propName = (String) element;
        if (!propName.equals(ServerTags.LOCATION) &&
            !propName.equals(ServerTags.CONTEXT_ROOT) &&
            !propName.equals(ServerTags.OBJECT_TYPE) &&
            !propName.equals(ServerTags.DIRECTORY_DEPLOYED) &&
            !propName.startsWith(
                DeploymentProperties.APP_CONFIG))
                {
            if (appProps.getProperty(propName) != null) {
                Property prop = app.createChild(Property.class);
                app.getProperty().add(prop);
                prop.setName(propName);
                prop.setValue(appProps.getProperty(propName));
            }
        }
      }
    }

    @Override
    public void unregisterAppFromDomainXML(final String appName,
        final String target) throws TransactionFailure {
        unregisterAppFromDomainXML(appName, target, false);
    }

    @Override
    public void unregisterAppFromDomainXML(final String appName,
        final String tgt, final boolean appRefOnly)
        throws TransactionFailure {
        ConfigSupport.apply(new SingleConfigCode() {
            @Override
            public Object run(ConfigBeanProxy param) throws PropertyVetoException, TransactionFailure {
                // get the transaction
                Transaction t = Transaction.getTransaction(param);
                if (t!=null) {
                    List targets = new ArrayList<>();
                    if (!DeploymentUtils.isDomainTarget(tgt)) {
                        targets.add(tgt);
                    } else {
                        targets = domain.getAllReferencedTargetsForApplication(appName);
                    }

                    Domain dmn;
                    if (param instanceof Domain) {
                        dmn = (Domain)param;
                    } else {
                        return Boolean.FALSE;
                    }

                    for (String target : targets) {
                        Server servr = dmn.getServerNamed(target);
                        if (servr != null) {
                            // remove the application-ref from standalone
                            // server instance
                            ConfigBeanProxy servr_w = t.enroll(servr);
                            for (ApplicationRef appRef :
                                servr.getApplicationRef()) {
                                if (appRef.getRef().equals(appName)) {
                                    ((Server)servr_w).getApplicationRef().remove(
                                        appRef);
                                    break;
                                }
                            }
                        }

                        Cluster cluster = dmn.getClusterNamed(target);
                        if (cluster != null) {
                            // remove the application-ref from cluster
                            ConfigBeanProxy cluster_w = t.enroll(cluster);
                            for (ApplicationRef appRef :
                                cluster.getApplicationRef()) {
                                if (appRef.getRef().equals(appName)) {
                                    ((Cluster)cluster_w).getApplicationRef().remove(
                                            appRef);
                                        break;
                                }
                            }

                            // remove the application-ref from cluster instances
                            for (Server svr : cluster.getInstances() ) {
                                ConfigBeanProxy svr_w = t.enroll(svr);
                                for (ApplicationRef appRef :
                                    svr.getApplicationRef()) {
                                    if (appRef.getRef().equals(appName)) {
                                        ((Server)svr_w).getApplicationRef(
                                           ).remove(appRef);
                                        break;
                                    }
                                }
                            }
                        }

                        DeploymentGroup dg = dmn.getDeploymentGroupNamed(target);
                        if (dg != null) {
                            // remove the application-ref from cluster
                            ConfigBeanProxy dg_w = t.enroll(dg);
                            for (ApplicationRef appRef :
                                dg.getApplicationRef()) {
                                if (appRef.getRef().equals(appName)) {
                                    ((DeploymentGroup)dg_w).getApplicationRef().remove(
                                            appRef);
                                        break;
                                }
                            }
                            // remove the application-ref from deployment group instances
                            // only if the server is not also a target (i.e. domain undeploy)
                            for (Server svr : dg.getInstances() ) {
                                if (!targets.contains(svr.getName())) {
                                    ConfigBeanProxy svr_w = t.enroll(svr);
                                    for (ApplicationRef appRef :
                                        svr.getApplicationRef()) {
                                        if (appRef.getRef().equals(appName)) {
                                            ((Server)svr_w).getApplicationRef(
                                               ).remove(appRef);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (!appRefOnly) {
                        // remove application element
                        Applications apps = dmn.getApplications();
                        ConfigBeanProxy apps_w = t.enroll(apps);
                        for (ApplicationName module : apps.getModules()) {
                            if (module.getName().equals(appName)) {
                                ((Applications)apps_w).getModules().remove(module);
                                break;
                            }
                        }
                    }
                }
                return Boolean.TRUE;
            }
        }, domain);
    }


    @Override
    public void updateAppEnabledAttributeInDomainXML(final String appName,
        final String target, final boolean enabled) throws TransactionFailure {
        ConfigSupport.apply(new SingleConfigCode() {
            @Override
            public Object run(ConfigBeanProxy param) throws PropertyVetoException, TransactionFailure {
                // get the transaction
                Transaction t = Transaction.getTransaction(param);
                if (t!=null) {
                    Domain dmn;
                    if (param instanceof Domain) {
                        dmn = (Domain)param;
                    } else {
                        return Boolean.FALSE;
                    }

                    if (enabled || DeploymentUtils.isDomainTarget(target)) {
                        Application app = dmn.getApplications().getApplication(appName);
                        ConfigBeanProxy app_w = t.enroll(app);
                       ((Application)app_w).setEnabled(String.valueOf(enabled));

                    }

                    List targets = new ArrayList<>();
                    if (!DeploymentUtils.isDomainTarget(target)) {
                        targets.add(target);
                    } else {
                        targets = domain.getAllReferencedTargetsForApplication(appName);
                    }

                    for (String target : targets) {
                        Server servr = dmn.getServerNamed(target);
                        if (servr != null) {
                            // update the application-ref from standalone
                            // server instance
                            for (ApplicationRef appRef :
                                servr.getApplicationRef()) {
                                if (appRef.getRef().equals(appName)) {
                                    ConfigBeanProxy appRef_w = t.enroll(appRef);
                                    ((ApplicationRef)appRef_w).setEnabled(String.valueOf(enabled));
                                    break;
                                }
                            }
                            updateClusterAppRefWithInstanceUpdate(t, servr, appName, enabled);
                        }
                        Cluster cluster = dmn.getClusterNamed(target);
                        if (cluster != null) {
                            // update the application-ref from cluster
                            for (ApplicationRef appRef :
                                cluster.getApplicationRef()) {
                                if (appRef.getRef().equals(appName)) {
                                    ConfigBeanProxy appRef_w = t.enroll(appRef);
                                    ((ApplicationRef)appRef_w).setEnabled(String.valueOf(enabled));
                                    break;
                                }
                            }

                            // update the application-ref from cluster instances
                            for (Server svr : cluster.getInstances() ) {
                                for (ApplicationRef appRef :
                                    svr.getApplicationRef()) {
                                    if (appRef.getRef().equals(appName)) {
                                        ConfigBeanProxy appRef_w = t.enroll(appRef);
                                        ((ApplicationRef)appRef_w).setEnabled(String.valueOf(enabled));
                                        break;
                                    }
                                }
                            }
                        }
                        
                        DeploymentGroup deploymentGroup = dmn.getDeploymentGroupNamed(target);
                        if (deploymentGroup != null) {
                            // update the application-ref from Deployment Group
                            for (ApplicationRef appRef
                                    : deploymentGroup.getApplicationRef()) {
                                if (appRef.getRef().equals(appName)) {
                                    ConfigBeanProxy appRef_w = t.enroll(appRef);
                                    ((ApplicationRef) appRef_w).setEnabled(String.valueOf(enabled));
                                    break;
                                }
                            }

                            // update the application-ref from Deployment Group instances
                            for (Server svr : deploymentGroup.getInstances()) {
                                for (ApplicationRef appRef
                                        : svr.getApplicationRef()) {
                                    if (appRef.getRef().equals(appName)) {
                                        ConfigBeanProxy appRef_w = t.enroll(appRef);
                                        ((ApplicationRef) appRef_w).setEnabled(String.valueOf(enabled));
                                        break;
                                    }
                                }
                            }
                        }
                    }
             }
             return Boolean.TRUE;
            }
        }, domain);
    }

    // check if the application is registered in domain.xml
    @Override
    public boolean isRegistered(String appName) {
        return applications.getApplication(appName)!=null;
    }

    @Override
    public ApplicationInfo get(String appName) {
        return appRegistry.get(appName);
    }

    private boolean isPaaSEnabled(Boolean isClassicStyle) {
        if (isClassicStyle) {
            return false;
        }

        return virtEnv != null && virtEnv.isPaasEnabled();
    }

    // gets the default target when no target is specified for non-paas case
    @Override
    public String getDefaultTarget(Boolean isClassicStyle) {
        if (!isPaaSEnabled(isClassicStyle)) {
            return DeploymentUtils.DAS_TARGET_NAME;
        }
        return null;
    }

    // gets the default target when no target is specified
    @Override
    public String getDefaultTarget(String appName, OpsParams.Origin origin, Boolean isClassicStyle) {
        if (!isPaaSEnabled(isClassicStyle)) {
            return DeploymentUtils.DAS_TARGET_NAME;
        } else {
           // for deploy case, OE will set the deploy target later
           if (origin == OpsParams.Origin.deploy) {
              return null;
           }
           // for other cases, we try to derive it from domain.xml
           List targets =
               domain.getAllReferencedTargetsForApplication(appName);
           if (targets.isEmpty()) {
               throw new IllegalArgumentException("Application not registered");
           }
           if (targets.size() > 1) {
               throw new IllegalArgumentException("Cannot determine the default target. Please specify an explicit target for the operation.");
           }
           return targets.get(0);
        }
    }

    public class DeploymentContextBuidlerImpl implements DeploymentContextBuilder {
        private final Logger logger;
        private final ActionReport report;
        private final OpsParams params;
        private File sFile;
        private ReadableArchive sArchive;
        private ArchiveHandler handler;

        public DeploymentContextBuidlerImpl(Logger logger, OpsParams params, ActionReport report) {
            this.logger = logger;
            this.report = report;
            this.params = params;
        }

        public DeploymentContextBuidlerImpl(DeploymentContextBuilder b) throws IOException {
            this.logger = b.logger();
            this.report = b.report();
            this.params = b.params();
            ReadableArchive archive = getArchive(b);
            source(archive);
            handler = b.archiveHandler();
        }

        @Override
        public DeploymentContextBuilder source(File source) {
            this.sFile = source;
            return this;
        }

        @Override
        public File sourceAsFile() {
            return sFile;
        }
        @Override
        public ReadableArchive sourceAsArchive() {
            return sArchive;
        }

        @Override
        public ArchiveHandler archiveHandler() {
            return handler;
        }

        @Override
        public DeploymentContextBuilder source(ReadableArchive archive) {
            this.sArchive = archive;
            return this;
        }

        @Override
        public DeploymentContextBuilder archiveHandler(ArchiveHandler handler) {
            this.handler = handler;
            return this;
        }

        @Override
        public ExtendedDeploymentContext build() throws IOException {
            return build(null);
        }
        @Override
        public Logger logger() { return logger; }
        @Override
        public ActionReport report() { return report; }
        @Override
        public OpsParams params() { return params; }

        @Override
        public ExtendedDeploymentContext build(ExtendedDeploymentContext initialContext) throws IOException {
            return ApplicationLifecycle.this.getContext(initialContext, this);
        }
    }

    @Override
    public DeploymentContextBuilder getBuilder(Logger logger, OpsParams params, ActionReport report) {
        return new DeploymentContextBuidlerImpl(logger, params, report);
    }

    /**
     * Updates the "enabled" setting of the cluster's app ref for the
     * given app if a change to the "enabled" setting of the app ref on one of
     * the cluster's instances implies a cluster-level change.
     * 

* If the app is enabled on any single instance in a cluster * then the cluster state needs to be enabled. If * the app is disabled on all instances in the cluster * then the cluster state should be disabled. This method makes sure the * cluster-level app ref enabled state is correct, given the current values * of the app refs on the cluster's instances combined with the new value * for the specified instance. * * @param t current config Transaction in progress * @param servr the Server for which the app ref has been enabled or disabled * @param appName the name of the app whose app ref has been enabled or disabled * @param isNewInstanceAppRefStateEnabled whether the new instance app ref state is enabled (false if disabled) */ private void updateClusterAppRefWithInstanceUpdate( final Transaction t, final Server servr, final String appName, final boolean isNewInstanceAppRefStateEnabled) throws TransactionFailure, PropertyVetoException { final Cluster clusterContainingInstance = servr.getCluster(); if (clusterContainingInstance != null) { /* * Update the cluster state also if needed. */ boolean isAppRefEnabledOnAnyClusterInstance = false; for (Server inst : clusterContainingInstance.getInstances()) { /* * The app ref for the server just changed above * still has its old state when fetched using * inst.getApplicationRef(appName). So when we * encounter the same server in the list of * cluster instances, use the "enabled" value -- * which we just used above to update the app ref * for the targeted instance -- below when * we need to consider the "enabled" value for the * just-changed instance. */ isAppRefEnabledOnAnyClusterInstance |= ( servr.getName().equals(inst.getName()) ? isNewInstanceAppRefStateEnabled : Boolean.parseBoolean(inst.getApplicationRef(appName).getEnabled())); } final ApplicationRef clusterAppRef = clusterContainingInstance.getApplicationRef(appName); if (Boolean.parseBoolean(clusterAppRef.getEnabled()) != isAppRefEnabledOnAnyClusterInstance) { t.enroll(clusterAppRef).setEnabled(String.valueOf(isAppRefEnabledOnAnyClusterInstance)); } } } // cannot put it on the builder itself since the builder is an official API. private ReadableArchive getArchive(DeploymentContextBuilder builder) throws IOException { ReadableArchive archive = builder.sourceAsArchive(); if (archive==null && builder.sourceAsFile()==null) { throw new IOException("Source archive or file not provided to builder"); } if (archive==null && builder.sourceAsFile()!=null) { archive = habitat.getService(ArchiveFactory.class).openArchive(builder.sourceAsFile()); if (archive==null) { throw new IOException("Invalid archive type : " + builder.sourceAsFile().getAbsolutePath()); } } return archive; } private ExtendedDeploymentContext getContext(ExtendedDeploymentContext initial, DeploymentContextBuilder builder) throws IOException { DeploymentContextBuilder copy = new DeploymentContextBuidlerImpl(builder); ReadableArchive archive = getArchive(copy); copy.source(archive); if (initial==null) { initial = new DeploymentContextImpl(copy, env); } ArchiveHandler archiveHandler = copy.archiveHandler(); if (archiveHandler == null) { String type = null; OpsParams params = builder.params(); if (params != null) { if (params instanceof DeployCommandParameters) { type = ((DeployCommandParameters)params).type; } else if (params instanceof UndeployCommandParameters) { type = ((UndeployCommandParameters)params)._type; } } archiveHandler = getArchiveHandler(archive, type); } // this is needed for autoundeploy to find the application // with the archive name File sourceFile = new File(archive.getURI().getSchemeSpecificPart()); initial.getAppProps().put(ServerTags.DEFAULT_APP_NAME, DeploymentUtils.getDefaultEEName(sourceFile.getName())); if (!(sourceFile.isDirectory())) { String repositoryBitName = copy.params().name(); try { repositoryBitName = VersioningUtils.getRepositoryName(repositoryBitName); } catch (VersioningSyntaxException e) { ActionReport report = copy.report(); report.setMessage(e.getMessage()); report.setActionExitCode(ActionReport.ExitCode.FAILURE); } // create a temporary deployment context File expansionDir = new File(domain.getApplicationRoot(), repositoryBitName); if (!expansionDir.mkdirs()) { /* * On Windows especially a previous directory might have * remainded after an earlier undeployment, for example if * a JAR file in the earlier deployment had been locked. * Warn but do not fail in such a case. */ logger.fine(localStrings.getLocalString("deploy.cannotcreateexpansiondir", "Error while creating directory for jar expansion: {0}",expansionDir)); } try { Long start = System.currentTimeMillis(); final WritableArchive expandedArchive = archiveFactory.createArchive(expansionDir); archiveHandler.expand(archive, expandedArchive, initial); if (logger.isLoggable(Level.FINE)) { logger.log(FINE, "Deployment expansion took {0}", System.currentTimeMillis() - start); } // Close the JAR archive before losing the reference to it or else the JAR remains locked. try { archive.close(); } catch(IOException e) { logger.log(SEVERE, KernelLoggerInfo.errorClosingArtifact, new Object[] { archive.getURI().getSchemeSpecificPart(), e}); throw e; } archive = (FileArchive) expandedArchive; initial.setSource(archive); } catch(IOException e) { logger.log(SEVERE, KernelLoggerInfo.errorExpandingFile, e); throw e; } } initial.setArchiveHandler(archiveHandler); return initial; } private void setAppRefAttributes(ApplicationRef appRef, DeployCommandParameters deployParams) throws PropertyVetoException { appRef.setRef(deployParams.name); if (deployParams.virtualservers != null) { appRef.setVirtualServers(deployParams.virtualservers); } else { // deploy to all virtual-servers, we need to get the list. appRef.setVirtualServers(DeploymentUtils.getVirtualServers(deployParams.target, env, domain)); } if(deployParams.lbenabled != null){ appRef.setLbEnabled(deployParams.lbenabled); } else { //check if system property exists and use that String lbEnabledDefault = System.getProperty(Server.lbEnabledSystemProperty); if (lbEnabledDefault != null) { appRef.setLbEnabled(lbEnabledDefault); } } appRef.setEnabled(deployParams.enabled.toString()); } @Override public ParameterMap prepareInstanceDeployParamMap(DeploymentContext dc) throws Exception { final DeployCommandParameters params = dc.getCommandParameters(DeployCommandParameters.class); final Collection excludedParams = new ArrayList<>(); excludedParams.add(DeploymentProperties.PATH); excludedParams.add(DeploymentProperties.DEPLOYMENT_PLAN); excludedParams.add(DeploymentProperties.ALT_DD); excludedParams.add(DeploymentProperties.RUNTIME_ALT_DD); excludedParams.add(DeploymentProperties.UPLOAD); // We'll force it to true ourselves. final ParameterMap paramMap; final ParameterMapExtractor extractor = new ParameterMapExtractor(params); paramMap = extractor.extract(excludedParams); prepareGeneratedContent(dc, paramMap); // set the path and plan params // get the location properties from the application so the token // will be resolved Application application = applications.getApplication(params.name); Properties appProperties = application.getDeployProperties(); String archiveLocation = appProperties.getProperty(Application.APP_LOCATION_PROP_NAME); final File archiveFile = new File(new URI(archiveLocation)); paramMap.set("DEFAULT", archiveFile.getAbsolutePath()); String planLocation = appProperties.getProperty(Application.DEPLOYMENT_PLAN_LOCATION_PROP_NAME); if (planLocation != null) { final File actualPlan = new File(new URI(planLocation)); paramMap.set(DeployCommandParameters.ParameterNames.DEPLOYMENT_PLAN, actualPlan.getAbsolutePath()); } String altDDLocation = appProperties.getProperty(Application.ALT_DD_LOCATION_PROP_NAME); if (altDDLocation != null) { final File altDD = new File(new URI(altDDLocation)); paramMap.set(DeployCommandParameters.ParameterNames.ALT_DD, altDD.getAbsolutePath()); } String runtimeAltDDLocation = appProperties.getProperty(Application.RUNTIME_ALT_DD_LOCATION_PROP_NAME); if (runtimeAltDDLocation != null) { final File runtimeAltDD = new File(new URI(runtimeAltDDLocation)); paramMap.set(DeployCommandParameters.ParameterNames.RUNTIME_ALT_DD, runtimeAltDD.getAbsolutePath()); } // always upload the archives to the instance side // but not directories. Note that we prepare a zip file containing // the generated directories and pass that as a single parameter so it // will be uploaded even though a deployment directory is not. paramMap.set(DeploymentProperties.UPLOAD, "true"); // pass the params we restored from the previous deployment in case of // redeployment if (params.previousContextRoot != null) { paramMap.set(DeploymentProperties.PRESERVED_CONTEXT_ROOT, params.previousContextRoot); } // pass the app props so we have the information to persist in the // domain.xml Properties appProps = dc.getAppProps(); appProps.remove(DeploymentProperties.APP_CONFIG); paramMap.set(DeploymentProperties.APP_PROPS, extractor.propertiesValue(appProps, ':')); Properties previousVirtualServers = dc.getTransientAppMetaData(DeploymentProperties.PREVIOUS_VIRTUAL_SERVERS, Properties.class); if (previousVirtualServers != null) { paramMap.set(DeploymentProperties.PREVIOUS_VIRTUAL_SERVERS, extractor.propertiesValue(previousVirtualServers, ':')); } Properties previousEnabledAttributes = dc.getTransientAppMetaData(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, Properties.class); if (previousEnabledAttributes != null) { paramMap.set(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, extractor.propertiesValue(previousEnabledAttributes, ':')); } return paramMap; } private void prepareGeneratedContent(final DeploymentContext dc, final ParameterMap paramMap) throws IOException { /* * Create a single ZIP file containing the various generated * directories for this app. * * Note that some deployments - such as of OSGI modules - might not * create any generated content. */ final File generatedContentZip = createGeneratedContentZip(); ZipOutputStream zipOS = null; /* * We want the ZIP file to contain xml/(appname), ejb/(appname), etc. * directories, even if those directories don't contain anything. * Then the instance deploy command can expand the uploaded zip file * based at the instance's generated/ directory and the files - including * empty directories if appropriate - will be stored in the right places. */ final File baseDir = dc.getScratchDir("xml").getParentFile().getParentFile(); for (String scratchType : UPLOADED_GENERATED_DIRS) { zipOS = addScratchContentIfPresent(dc, baseDir, zipOS, generatedContentZip, scratchType); } if (zipOS != null) { /* * Because we did zip up some generated content, add the just-generated * zip file as a parameter to the param map. */ zipOS.close(); // set the generated content param paramMap.set("generatedcontent", generatedContentZip.getAbsolutePath()); } } private File createGeneratedContentZip() throws IOException { final File tempFile = File.createTempFile("gendContent", ".zip"); FileUtils.deleteOnExit(tempFile); return tempFile; } private ZipOutputStream addScratchContentIfPresent(final DeploymentContext dc, final File baseDir, ZipOutputStream zipOS, final File generatedContentZip, final String scratchDirName) throws IOException { final File genDir = dc.getScratchDir(scratchDirName); if (genDir.isDirectory()) { if (zipOS == null) { zipOS = new ZipOutputStream( new BufferedOutputStream(new FileOutputStream(generatedContentZip))); } addFileToZip(zipOS, baseDir, genDir); } return zipOS; } private void addFileToZip(final ZipOutputStream zipOS, final File baseDir, final File f) throws IOException { final String entryName = baseDir.toURI().relativize(f.toURI()).getPath(); final ZipEntry entry = new ZipEntry(entryName); zipOS.putNextEntry(entry); if ( ! f.isDirectory()) { final byte[] buffer = new byte[1024]; final InputStream is = new BufferedInputStream(new FileInputStream(f)); int bytesRead; try { while ((bytesRead = is.read(buffer)) != -1) { zipOS.write(buffer, 0, bytesRead); } } finally { is.close(); zipOS.closeEntry(); } } else { /* * A directory entry has no content itself. */ zipOS.closeEntry(); for (File subFile : f.listFiles()) { addFileToZip(zipOS, baseDir, subFile); } } } @Override public void validateDeploymentTarget(String target, String name, boolean isRedeploy) { List referencedTargets = domain.getAllReferencedTargetsForApplication(name); if (referencedTargets.isEmpty()) { if (isRegistered(name)) { if (!isRedeploy && DeploymentUtils.isDomainTarget(target)) { throw new IllegalArgumentException(localStrings.getLocalString("application.alreadyreg.redeploy", "Application with name {0} is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name.", name)); } else { if (!DeploymentUtils.isDomainTarget(target)) { throw new IllegalArgumentException(localStrings.getLocalString("use.create_app_ref_2", "Application {0} is already deployed in this domain. Please use create application ref to create application reference on target {1}.", name, target)); } } } return; } if (!isRedeploy) { if (DeploymentUtils.isDomainTarget(target)) { throw new IllegalArgumentException(localStrings.getLocalString("application.deploy_domain", "Application with name {0} is already referenced by other target(s). Please specify force option to redeploy to domain.", name)); } if (referencedTargets.size() == 1 && referencedTargets.contains(target)) { throw new IllegalArgumentException(localStrings.getLocalString("application.alreadyreg.redeploy", "Application with name {0} is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name.", name)); } else { throw new IllegalArgumentException(localStrings.getLocalString("use.create_app_ref", "Application {0} is already referenced by other target(s). Please use create application ref to create application reference on target {1}.", name, target)); } } else { if (referencedTargets.size() == 1 && referencedTargets.contains(target)) { return; } else { if (!DeploymentUtils.isDomainTarget(target) && domain.getDeploymentGroupNamed(target) == null) { throw new IllegalArgumentException(localStrings.getLocalString("redeploy_on_multiple_targets", "Application {0} is referenced by more than one targets. Please remove other references or specify all targets (or domain target if using asadmin command line) before attempting redeploy operation.", name)); } } } } @Override public void validateUndeploymentTarget(String target, String name) { List referencedTargets = domain.getAllReferencedTargetsForApplication(name); if (referencedTargets.size() > 1) { Application app = applications.getApplication(name); if (!DeploymentUtils.isDomainTarget(target) && domain.getDeploymentGroupNamed(target) == null) { if (app.isLifecycleModule()) { throw new IllegalArgumentException(localStrings.getLocalString("delete_lifecycle_on_multiple_targets", "Lifecycle module {0} is referenced by more than one targets. Please remove other references before attempting delete operation.", name)); } else { throw new IllegalArgumentException(localStrings.getLocalString("undeploy_on_multiple_targets", "Application {0} is referenced by more than one targets. Please remove other references or specify all targets (or domain target if using asadmin command line) before attempting undeploy operation.", name)); } } } } @Override public void validateSpecifiedTarget(String target) { if (env.isDas()) { if (target == null) { // we only validate the specified target return; } Cluster cluster = domain.getClusterNamed(target); if (cluster != null) { if (cluster.isVirtual()) { throw new IllegalArgumentException(localStrings.getLocalString("cannot_specify_managed_target", "Cannot specify target {0} for the operation. Target {0} is a managed target.", target)); } } } } @Override public boolean isAppEnabled(Application app) { if (Boolean.valueOf(app.getEnabled())) { ApplicationRef appRef = server.getApplicationRef(app.getName()); if (appRef != null && Boolean.valueOf(appRef.getEnabled())) { return true; } } return false; } @Override public ExtendedDeploymentContext disable(UndeployCommandParameters commandParams, Application app, ApplicationInfo appInfo, ActionReport report, Logger logger) throws Exception { if (appInfo == null) { report.failure(logger, "Application not registered", null); return null; } // if it's not on DAS and the application is not loaded, do not unload // when it's on DAS, there is some necessary clean up we need to do if (!env.isDas() && !appInfo.isLoaded()) { return null; } if (app != null) { commandParams._type = app.archiveType(); } final ExtendedDeploymentContext deploymentContext = getBuilder(logger, commandParams, report).source(appInfo.getSource()).build(); if (app != null) { deploymentContext.getAppProps().putAll( app.getDeployProperties()); deploymentContext.setModulePropsMap( app.getModulePropertiesMap()); } if (commandParams.properties != null) { deploymentContext.getAppProps().putAll(commandParams.properties); } unload(appInfo, deploymentContext); return deploymentContext; } @Override public ExtendedDeploymentContext enable(String target, Application app, ApplicationRef appRef, ActionReport report, Logger logger) throws Exception { ReadableArchive archive = null; try { DeployCommandParameters commandParams = app.getDeployParameters(appRef); // if the application is already loaded, do not load again ApplicationInfo appInfo = appRegistry.get(commandParams.name); if (appInfo != null && appInfo.isLoaded()) { return null; } commandParams.origin = DeployCommandParameters.Origin.load; commandParams.command = DeployCommandParameters.Command.enable; commandParams.target = target; commandParams.enabled = Boolean.TRUE; Properties contextProps = app.getDeployProperties(); Map modulePropsMap = app.getModulePropertiesMap(); ApplicationConfigInfo savedAppConfig = new ApplicationConfigInfo(app); URI uri = new URI(app.getLocation()); File file = new File(uri); if (!file.exists()) { throw new Exception(localStrings.getLocalString("fnf", "File not found {0}", file.getAbsolutePath())); } archive = archiveFactory.openArchive(file); final ExtendedDeploymentContext deploymentContext = getBuilder(logger, commandParams, report).source(archive).build(); Properties appProps = deploymentContext.getAppProps(); appProps.putAll(contextProps); savedAppConfig.store(appProps); if (modulePropsMap != null) { deploymentContext.setModulePropsMap(modulePropsMap); } deploy(getSniffersFromApp(app), deploymentContext); return deploymentContext; } finally { try { if (archive != null) { archive.close(); } } catch (IOException ioe) { // ignore } } } private boolean loadOnCurrentInstance(DeploymentContext context) { final DeployCommandParameters commandParams = context.getCommandParameters(DeployCommandParameters.class); final Properties appProps = context.getAppProps(); if (commandParams.enabled) { // if the current instance match with the target if (domain.isCurrentInstanceMatchingTarget(commandParams.target, commandParams.name(), server.getName(), context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_TARGETS, List.class))) { return true; } if (server.isDas()) { String objectType = appProps.getProperty(ServerTags.OBJECT_TYPE); if (objectType != null) { // if it's a system application needs to be loaded on DAS if (objectType.equals(DeploymentProperties.SYSTEM_ADMIN) || objectType.equals(DeploymentProperties.SYSTEM_ALL)) { return true; } } } } return false; } private String getApplicationType(ApplicationInfo appInfo) { StringBuilder sb = new StringBuilder(); if (appInfo.getSniffers().size() > 0) { for (Sniffer sniffer : appInfo.getSniffers()) { if (sniffer.isUserVisible()) { sb.append(sniffer.getModuleType()).append(", "); } } } if (sb.length() > 2) { return sb.substring(0, sb.length()-2); } return sb.toString(); } @Override public List getSniffersFromApp(Application app) { List snifferTypes = new ArrayList<>(); for (com.sun.enterprise.config.serverbeans.Module module : app.getModule()) { for (Engine engine : module.getEngines()) { snifferTypes.add(engine.getSniffer()); } } if (snifferTypes.isEmpty()) { // for the upgrade scenario, we cannot get the sniffers from the // domain.xml, so we need to re-process it during deployment return null; } List sniffers = new ArrayList<>(); if (app.isStandaloneModule()) { for (String snifferType : snifferTypes) { Sniffer sniffer = snifferManager.getSniffer(snifferType); if (sniffer != null) { sniffers.add(sniffer); } else { logger.log(SEVERE, KernelLoggerInfo.cantFindSniffer, snifferType); } } if (sniffers.isEmpty()) { logger.log(SEVERE, KernelLoggerInfo.cantFindSnifferForApp, app.getName()); return null; } } else { // todo, this is a cludge to force the reload and reparsing of the // composite application. return null; } return sniffers; } private ExecutorService createExecutorService() { Runtime runtime = Runtime.getRuntime(); int nrOfProcessors = runtime.availableProcessors(); return new ThreadPoolExecutor(0, nrOfProcessors, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setName("deployment-jar-scanner"); t.setContextClassLoader(getClass().getClassLoader()); t.setDaemon(true); return t; } }); } @Override public ExtendedDeploymentContext getCurrentDeploymentContext() { return currentDeploymentContext.get().peek(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy