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

org.glassfish.internal.data.ModuleInfo Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-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-2021] [Payara Foundation and/or its affiliates]

package org.glassfish.internal.data;

import com.sun.enterprise.config.serverbeans.Engine;
import com.sun.enterprise.config.serverbeans.Module;
import com.sun.enterprise.config.serverbeans.ServerTags;
import com.sun.enterprise.util.ExceptionUtil;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import java.util.logging.Logger;
import org.glassfish.api.container.Container;
import org.glassfish.api.container.Sniffer;
import org.glassfish.api.deployment.ApplicationContainer;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.Deployer;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.event.EventListener.Event;
import org.glassfish.api.event.Events;
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.StructuredDeploymentTracing;
import org.glassfish.internal.deployment.analysis.TraceContext;
import org.jvnet.hk2.config.TransactionFailure;
import org.jvnet.hk2.config.types.Property;

/**
 * Each module of an application has an associated module info instance keeping
 * the list of engines in which that module is loaded.
 *
 * @author Jerome Dochez
 */
public class ModuleInfo {

    protected Set engines = new LinkedHashSet<>();

    // The reversed engines contain the same elements as engines but just in
    // reversed order, they are used when stopping/unloading the module.
    // The engines should be stopped/unloaded in the reverse order of what
    // they were originally loaded/started.
    protected LinkedList reversedEngines = new LinkedList<>();

    final protected Map, Object> metaData = new HashMap<>();

    protected final String name;
    protected final Events events;
    private Properties moduleProps;
    private boolean loaded = false;
    private boolean started = false;
    private ClassLoader moduleClassLoader;
    private Set classLoaders = new HashSet<>();
    
  
    public ModuleInfo(final Events events, String name, Collection refs, 
        Properties moduleProps) {
        this.name = name;
        this.events = events;
        for (EngineRef ref : refs) {
            engines.add(ref);
        }
        for (EngineRef ref : refs) {
            reversedEngines.addFirst(ref);
        }
        this.moduleProps = moduleProps;
    }

    public Set getEngineRefs() {
        Set copy = new LinkedHashSet<>();
        copy.addAll(_getEngineRefs());
        return copy; 
    }

    protected Set _getEngineRefs() {
        return engines;
    }

    public Set getClassLoaders() {
        return classLoaders;
    }
    
    public ClassLoader getModuleClassLoader() {
        return moduleClassLoader;
    }

    protected void cleanClassLoaders() {
        classLoaders.clear();
        moduleClassLoader = null;
    }

    public void addMetaData(Object o) {
        metaData.put(o.getClass(), o);
    }

    public  T getMetaData(Class c) {
        return c.cast(metaData.get(c));
    }

    public Object getMetaData(String className) {
        for (Entry, Object> entry : metaData.entrySet()) {
            if (entry.getKey().getName().equals(className)) {
                return entry.getValue();
            }
        }
        return null;
    }

    public String getName() {
        return name;
    }

    public boolean isRunning() {
        return started;
    }

    public boolean isLoaded() {
        return loaded;
    }

    public Properties getModuleProps() {
        Properties props =  new Properties();
        if (moduleProps != null) {
            props.putAll(moduleProps);
        }
        return props;
    }


    /**
     * Returns the list of sniffers that participated in loaded this
     * application
     *
     * @return array of sniffer that loaded the application's module
     */
    public Collection getSniffers() {
        List sniffers = new ArrayList<>();
        for (EngineRef engine : _getEngineRefs()) {
            sniffers.add(engine.getContainerInfo().getSniffer());
        }
        return sniffers;
    }

    public void load(ExtendedDeploymentContext context, ProgressTracker tracker) throws Exception {
        Logger logger = context.getLogger();
        context.setPhase(ExtendedDeploymentContext.Phase.LOAD);
        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);

        moduleClassLoader = context.getClassLoader();

        Set filteredEngines = new LinkedHashSet<>();
        LinkedList filteredReversedEngines = new LinkedList<>();

        ClassLoader currentClassLoader  = Thread.currentThread().getContextClassLoader();
        try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.MODULE, name, DeploymentTracing.AppStage.LOAD)){
            Thread.currentThread().setContextClassLoader(context.getClassLoader());
            for (EngineRef engine : _getEngineRefs()) {

                final EngineInfo engineInfo = engine.getContainerInfo();

                // get the container.
                Deployer deployer = engineInfo.getDeployer();

                try (DeploymentSpan containerSpan = tracing.startSpan(TraceContext.Level.CONTAINER, engineInfo.getSniffer().getModuleType(), DeploymentTracing.AppStage.LOAD)) {
                    ApplicationContainer appCtr = deployer.load(engineInfo.getContainer(), context);
                    if (appCtr == null) {
                        String msg = "Cannot load application in " + engineInfo.getContainer().getName() + " container";
                        logger.fine(msg);
                        continue;
                    }
                    engine.load(context, tracker);
                    engine.setApplicationContainer(appCtr);
                    filteredEngines.add(engine);
                    filteredReversedEngines.addFirst(engine);
                } catch (Exception e) {
                    logger.log(SEVERE, "Exception while invoking " + deployer.getClass() + " load method", e);
                    throw e;
                }
            }
            engines = filteredEngines;
            reversedEngines = filteredReversedEngines;

            if (events!=null) {
                try (DeploymentSpan innerSpan = tracing.startSpan(TraceContext.Level.MODULE, name,
                        DeploymentTracing.AppStage.PROCESS_EVENTS, Deployment.MODULE_LOADED.type())) {
                    events.send(new Event(Deployment.MODULE_LOADED, this), false);
                }
            }
        } finally {
            Thread.currentThread().setContextClassLoader(currentClassLoader);
        }

    }    

    /*
     * Returns the EngineRef for a particular container type
     * @param type the container type
     * @return the module info is this application as a module implemented with
     * the passed container type
     */
    public  EngineRef getEngineRefForContainer(Class type) {
        for (EngineRef engine : _getEngineRefs()) {
            T container = null;
            try {
                container = type.cast(engine.getContainerInfo().getContainer());
            } catch (Exception e) {
                // ignore, wrong container
            }
            if (container!=null) {
                return engine;
            }
        }
        return null;
    }


    public synchronized void start(
        DeploymentContext context,
        ProgressTracker tracker) throws Exception {

        Logger logger = context.getLogger();

        if (started)
            return;
        
        loaded = true;
        ClassLoader currentClassLoader  = 
            Thread.currentThread().getContextClassLoader();
        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);
        try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.MODULE, getName(), DeploymentTracing.AppStage.START)) {
            Thread.currentThread().setContextClassLoader(context.getClassLoader());
            // registers all deployed items.
            for (EngineRef engine : _getEngineRefs()) {
                if (logger.isLoggable(FINE)) {
                    logger.log(FINE, "starting {0}", engine.getContainerInfo().getSniffer().getModuleType());
                }

                try (DeploymentSpan innerSpan = tracing.startSpan(TraceContext.Level.CONTAINER,  engine.getContainerInfo().getSniffer().getModuleType(), DeploymentTracing.AppStage.START)){
                    if (!engine.start( context, tracker)) {
                        logger.log(SEVERE, "Module not started {0}", engine.getApplicationContainer().toString());
                        throw new Exception( "Module not started " +  engine.getApplicationContainer().toString());
                    }
                } catch(Exception e) { 
                    DeployCommandParameters dcp = context.getCommandParameters(DeployCommandParameters.class);
                    if(dcp.isSkipDSFailure() && ExceptionUtil.isDSFailure(e)){
                        logger.log(WARNING, "Resource communication failure exception skipped while invoking " + engine.getApplicationContainer().getClass() + " start method", e);
                    } else {
                        logger.log(SEVERE, "Exception while invoking " + engine.getApplicationContainer().getClass() + " start method", e);
                        throw e;
                    }
                }
            }
            started=true;
            if (events!=null) {
                try (DeploymentSpan innerSpan = tracing.startSpan(DeploymentTracing.AppStage.PROCESS_EVENTS, Deployment.MODULE_STARTED.type())) {
                    events.send(new Event(Deployment.MODULE_STARTED, this), false);
                }
            }
        } finally {
            Thread.currentThread().setContextClassLoader(currentClassLoader);
        }
    }

    public synchronized void stop(ExtendedDeploymentContext context, Logger logger) {

        if (!started)
            return;
        
        ClassLoader currentClassLoader  = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(moduleClassLoader);
            for (EngineRef engine : reversedEngines) {
                try {
                    context.setClassLoader(moduleClassLoader);
                    engine.stop(context);
                } catch(Exception e) {
                    logger.log(SEVERE, "Cannot stop module " +
                        engine.getContainerInfo().getSniffer().getModuleType(),e );
                }
            }
            started = false;
            loaded = false;
            if (events!=null) {
                events.send(new Event(Deployment.MODULE_STOPPED, this), false);
            }
        } finally {
            Thread.currentThread().setContextClassLoader(currentClassLoader);
        }
    }

    public synchronized void reload(
        DeploymentContext context,
        ProgressTracker tracker) throws Exception {

        Logger logger = context.getLogger();

        ClassLoader currentClassLoader  = 
            Thread.currentThread().getContextClassLoader();
        StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context);
        try (DeploymentSpan span = tracing.startSpan(TraceContext.Level.MODULE, getName(), DeploymentTracing.AppStage.START)) {
            Thread.currentThread().setContextClassLoader(context.getClassLoader());
            for (EngineRef engine : _getEngineRefs()) {
                if (logger.isLoggable(FINE)) {
                    logger.log(FINE, "Reloading {0}", engine.getContainerInfo().getSniffer().getModuleType());
                }

                try (DeploymentSpan innerSpan = tracing.startSpan(TraceContext.Level.CONTAINER,  engine.getContainerInfo().getSniffer().getModuleType(), DeploymentTracing.AppStage.START)){
                    if (!engine.reload( context, tracker)) {
                        logger.log(SEVERE, "Module not reloaded {0}", engine.getApplicationContainer().toString());
                        throw new Exception( "Module not reloaded " +  engine.getApplicationContainer().toString());
                    }
                } catch(Exception e) { 
                    DeployCommandParameters dcp = context.getCommandParameters(DeployCommandParameters.class);
                    if(dcp.isSkipDSFailure() && ExceptionUtil.isDSFailure(e)){
                        logger.log(WARNING, "Resource communication failure exception skipped while invoking " + engine.getApplicationContainer().getClass() + " start method", e);
                    } else {
                        logger.log(SEVERE, "Exception while invoking " + engine.getApplicationContainer().getClass() + " reload method", e);
                        throw e;
                    }
                }
            }
        } finally {
            Thread.currentThread().setContextClassLoader(currentClassLoader);
        }
    }

    public void unload(ExtendedDeploymentContext context) {

        Logger logger = context.getLogger();
        ClassLoader currentClassLoader  = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(moduleClassLoader);
            for (EngineRef engine : reversedEngines) {
                if (engine.getApplicationContainer() != null
                        && engine.getApplicationContainer().getClassLoader() != null) {
                    classLoaders.add(engine.getApplicationContainer().getClassLoader());
                    try {
                        context.setClassLoader(moduleClassLoader);
                        engine.unload(context);
                    } catch(Throwable e) {
                        logger.log(SEVERE, "Failed to unload from container type : " +
                            engine.getContainerInfo().getSniffer().getModuleType(), e);
                    }
                }
            }
            // add the module classloader to the predestroy list if it's not
            // already there
            if (classLoaders != null && moduleClassLoader != null) {
                classLoaders.add(moduleClassLoader);
            }
            if (events!=null) {
                events.send(new Event(Deployment.MODULE_UNLOADED, this), false);
            }
        } finally {
            Thread.currentThread().setContextClassLoader(currentClassLoader);
            context.setClassLoader(null);
        }
    }

    public void clean(ExtendedDeploymentContext context) throws Exception {
        for (EngineRef ref : reversedEngines) {
            ref.clean(context);
        }
        if (events!=null) {
            events.send(new Event(Deployment.MODULE_CLEANED,context), false);
        }        
        
    }

    public boolean suspend(Logger logger) {

        boolean isSuccess = true;

        for (EngineRef engine : reversedEngines) {
            try {
                engine.getApplicationContainer().suspend();
            } catch(Exception e) {
                isSuccess = false;
                logger.log(SEVERE, "Error suspending module " +
                           engine.getContainerInfo().getSniffer().getModuleType(),e );
            }
        }

        return isSuccess;
    }

    public boolean resume(Logger logger) {

        boolean isSuccess = true;

        for (EngineRef module : _getEngineRefs()) {
            try {
                module.getApplicationContainer().resume();
            } catch(Exception e) {
                isSuccess = false;
                logger.log(SEVERE, "Error resuming module " +
                           module.getContainerInfo().getSniffer().getModuleType(),e );
            }
        }

        return isSuccess;
    }

    /**
     * Saves its state to the configuration.this method must be called within a
     * transaction to the configured module instance.
     *
     * @param module the module being persisted
     * @throws org.jvnet.hk2.config.TransactionFailure
     * @throws java.beans.PropertyVetoException
     */
    public void save(Module module) throws TransactionFailure, PropertyVetoException {
        // write out the module properties only for composite app
        if (Boolean.valueOf(moduleProps.getProperty(
            ServerTags.IS_COMPOSITE))) {
            moduleProps.remove(ServerTags.IS_COMPOSITE);
            for (Iterator itr = moduleProps.keySet().iterator(); 
                itr.hasNext();) {
                String propName = (String) itr.next();
                Property prop = module.createChild(Property.class);
                module.getProperty().add(prop);
                prop.setName(propName);
                prop.setValue(moduleProps.getProperty(propName));
            }
        }

        for (EngineRef ref : _getEngineRefs()) {
            Engine engine = module.createChild(Engine.class);
            module.getEngines().add(engine);
            ref.save(engine);
        }
    }

    public void reset() {
        cleanClassLoaders();
        started = false;
        loaded = false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy