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

com.sun.enterprise.web.WebApplication 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-2016 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 [2020-2021] [Payara Foundation and/or its affiliates]

package com.sun.enterprise.web;

import com.sun.enterprise.deployment.EnvironmentProperty;
import com.sun.enterprise.deployment.web.ContextParameter;
import com.sun.enterprise.deployment.web.EnvironmentEntry;
import com.sun.enterprise.util.Result;
import com.sun.enterprise.web.session.PersistenceType;
import org.glassfish.api.deployment.ApplicationContainer;
import org.glassfish.api.deployment.ApplicationContext;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.UndeployCommandParameters;
import org.glassfish.internal.deployment.ExtendedDeploymentContext;
import org.glassfish.deployment.common.ApplicationConfigInfo;
import org.glassfish.deployment.common.DeploymentProperties;
import org.glassfish.web.LogFacade;
import org.glassfish.web.config.serverbeans.ContextParam;
import org.glassfish.web.config.serverbeans.EnvEntry;
import org.glassfish.web.deployment.descriptor.WebBundleDescriptorImpl;
import org.glassfish.web.deployment.runtime.SessionManager;
import org.glassfish.web.deployment.runtime.SunWebAppImpl;

import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class WebApplication implements ApplicationContainer {

    private static final Logger logger = LogFacade.getLogger();

    protected static final ResourceBundle rb = logger.getResourceBundle();

    private final WebContainer container;
    private final WebModuleConfig wmInfo;
    private final Set webModules = new HashSet();
    private final org.glassfish.web.config.serverbeans.WebModuleConfig appConfigCustomizations;

    public WebApplication(WebContainer container, WebModuleConfig config, 
            final ApplicationConfigInfo appConfigInfo) {
        this.container = container;
        this.wmInfo = config;
        this.appConfigCustomizations = extractCustomizations(appConfigInfo);
    }

    @Override
    public boolean start(ApplicationContext appContext) throws Exception {

        webModules.clear();

        Properties props = null;

        if (appContext!=null) {
            wmInfo.setAppClassLoader(appContext.getClassLoader());
            if (appContext instanceof DeploymentContext) {
                DeploymentContext deployContext = (DeploymentContext)appContext;
                wmInfo.setDeploymentContext(deployContext);
                if (isKeepState(deployContext, true)) {
                    props = deployContext.getAppProps();
                }
            }
            applyApplicationConfig(appContext);
        }

        List> results = container.loadWebModule(
            wmInfo, "null", props);
        // release DeploymentContext in memory
        wmInfo.setDeploymentContext(null);

        if (results.isEmpty()) {
            logger.log(Level.SEVERE, "webApplication.unknownError");
            return false;
        }

        boolean isFailure = false;
        StringBuilder sb = null;
        for (Result result : results) {
            if (result.isFailure()) {
                if (sb == null) {
                    sb = new StringBuilder(result.exception().toString());
                } else {
                    sb.append(result.exception().toString());
                }
                logger.log(Level.WARNING, result.exception().toString(),
                           result.exception());
                isFailure = true;
            } else {
                webModules.add(result.result());
            }
        }

        if (isFailure) {
            webModules.clear();
            throw new Exception(sb.toString());
        }

        if (logger.isLoggable(Level.INFO)) {
            logger.log(Level.INFO, LogFacade.LOADING_APP, new Object[] {wmInfo.getDescriptor().getName(), wmInfo.getDescriptor().getContextRoot()});
        }
        
        return true;
    }

    @Override
    public boolean stop(ApplicationContext stopContext) {

        if (stopContext instanceof DeploymentContext) {
            DeploymentContext deployContext = (DeploymentContext)stopContext;

            Properties props = null;
            boolean keepSessions = isKeepState(deployContext, false);
            if (keepSessions) {
                props = new Properties();
            }

            container.unloadWebModule(getDescriptor().getContextRoot(),
                                      getDescriptor().getApplication().getRegistrationName(),
                                      wmInfo.getVirtualServers(), props);

            if (keepSessions) {
                Properties actionReportProps = getActionReportProperties(deployContext);
                // should not be null here
                if (actionReportProps != null) {
                    actionReportProps.putAll(props);
                }
            }
        }

        stopCoherenceWeb();

        return true;
    }

    @Override
    public boolean reload(ApplicationContext context) throws Exception {
        webModules.forEach(WebModule::reload);
        return true;
    }

    /**
     * Suspends this application on all virtual servers.
     */
    @Override
    public boolean suspend() {
        return container.suspendWebModule(
            wmInfo.getDescriptor().getContextRoot(), "null", null);
    }

    /**
     * Resumes this application on all virtual servers.
     */
    @Override
    public boolean resume() throws Exception {
        // WebContainer.loadWebModule(), which is called by start(),
        // already checks if the web module has been suspended, and if so,
        // just resumes it and returns
        return start(null);
    }

    /**
     * Returns the class loader associated with this application
     *
     * @return ClassLoader for this app
     */
    @Override
    public ClassLoader getClassLoader() {
        return wmInfo.getAppClassLoader();
    }

    /**
     * Gets a set of all the WebModule instances (one per virtual
     * server deployment) of this WebApplication.
     * 
     * 

For each WebModule in the returned set, the corresponding * ServletContext may be obtained by calling WebModule#getServletContext */ public Set getWebModules() { return webModules; } /** * Returns the deployment descriptor associated with this application * * @return deployment descriptor if they exist or null if not */ @Override public WebBundleDescriptorImpl getDescriptor() { return wmInfo.getDescriptor(); } private boolean isKeepState(DeploymentContext deployContext, boolean isDeploy) { Boolean keepState = null; if (isDeploy) { DeployCommandParameters dcp = deployContext.getCommandParameters(DeployCommandParameters.class); if (dcp != null) { keepState = dcp.keepstate; } } else { UndeployCommandParameters ucp = deployContext.getCommandParameters(UndeployCommandParameters.class); if (ucp != null) { keepState = ucp.keepstate; } } if (keepState == null) { String keepSessionsString = deployContext.getAppProps().getProperty(DeploymentProperties.KEEP_SESSIONS); if (keepSessionsString != null && keepSessionsString.trim().length() > 0) { keepState = Boolean.valueOf(keepSessionsString); } else { keepState = getDescriptor().getApplication().getKeepState(); } } return ((keepState != null) ? keepState : false); } /** * Extracts the application config information for the web container * from the saved config info. The saved config info is from the * in-memory configuration (domain.xml) if this app was already deployed * and is being redeployed. * * @param appConfigInfo * @return */ private org.glassfish.web.config.serverbeans.WebModuleConfig extractCustomizations( final ApplicationConfigInfo appConfigInfo) { return appConfigInfo.get(trimmedModuleName(wmInfo.getName()), "web"); } private String trimmedModuleName(String moduleName) { final int hash = moduleName.indexOf('#'); if (hash == -1) { return moduleName; } return moduleName.substring(hash + 1); } /** * Applies application config customization (stored temporarily in the * start-up context's start-up parameters) to the web app's descriptor. * @param appContext */ private void applyApplicationConfig(ApplicationContext appContext) { WebBundleDescriptorImpl descriptor = wmInfo.getDescriptor(); try { if (appConfigCustomizations != null) { EnvEntryCustomizer envEntryCustomizer = new EnvEntryCustomizer( descriptor.getEnvironmentEntrySet(), appConfigCustomizations.getEnvEntry()); ContextParamCustomizer contextParamCustomizer = new ContextParamCustomizer( descriptor.getContextParametersSet(), appConfigCustomizations.getContextParam()); envEntryCustomizer.applyCustomizations(); contextParamCustomizer.applyCustomizations(); } } catch (ClassCastException ex) { /* * If the user specified an env-entry value that does not * work with the env-entry type it can cause a class cast * exception. Log the warning but continue working. */ logger.log(Level.WARNING, "", ex); } } @SuppressWarnings("unchecked") private Properties getActionReportProperties(DeploymentContext deployContext) { if (!wmInfo.getDescriptor().getApplication().isVirtual()) { deployContext = ((ExtendedDeploymentContext)deployContext).getParentContext(); } return deployContext.getActionReport().getExtraProperties(); } /* * Convenience class for applying customizations to descriptor items. *

* Much of the logic is the same for the different types of customizations - * and this class abstracts all the common behavior. This may seem like * overkill, factoring this logic out like this, but the applyCustomizations * logic is not something we want to have two copies of. */ private abstract class Customizer { protected Set descriptorItems; protected List customizations; private String descriptorItemName; private Customizer(Set descriptorItems, List customizations, String descriptorItemName) { this.descriptorItems = descriptorItems; this.customizations = customizations; this.descriptorItemName = descriptorItemName; } /** * Indicates whether the customization says to ignore any corresponding * descriptor entry. * @param customization the customization * @return true if the user wants to ignore any corresponding descriptor entry; false otherwise */ protected abstract boolean isIgnoreDescriptorItem(U customization); /** * Creates a new descriptor item using the information from the * customization. * @param customization the customization the gives the value(s) for the new descriptor * @return the new descriptor item */ protected abstract T newDescriptorItem(U customization); /** * Assigns the values from the customization to the existing descriptor * item. * @param descriptorItem descriptor item to change * @param customization customization containing the new values to be set in the descriptor item */ protected abstract void setDescriptorItemValue(T descriptorItem, U customization); /** * Returns the name from the descriptor item * @param descriptorItem * @return name from the descriptor item */ protected abstract String getName(T descriptorItem); /** * Returns the value from the descriptor item * @param descriptorItem * @return value from the descriptor item */ protected abstract String getValue(T descriptorItem); /** * Returns the name from the customization * @param customization * @return name from the customization */ protected abstract String getCustomizationName(U customization); /** * Represents the customization as a String for logging. * @param customization * @return */ protected abstract String toString(U customization); /** * Removes the descriptor item from the descriptor's collection * of this type of item. * * @param descriptorItem the item to remove */ protected void removeDescriptorItem(T descriptorItem) { descriptorItems.remove(descriptorItem); } /** * Adds a new descriptor item to the descriptor's collection of * items, basing the new one on the customization the user created. * * @param customization * @return the newly-created item */ protected T addDescriptorItem(U customization) { T newItem = newDescriptorItem(customization); descriptorItems.add(newItem); return newItem; } /** * Applies the set of customizations to the descriptor's set of * items. */ void applyCustomizations () { boolean isFiner = logger.isLoggable(Level.FINER); nextCustomization: for (U customization : customizations) { /* * For each customization try to find a descriptor item with * the same name. If there is one, either ignore the descriptor * item (if that is what the customization specifies) or override * the descriptor items'a value with the value from the * customization. */ for (Iterator it = descriptorItems.iterator(); it.hasNext();) { T descriptorItem = it.next(); String dItemName = getName(descriptorItem); String customizationItemName = getCustomizationName(customization); if (dItemName.equals(customizationItemName)) { /* * We found a descriptor item that matches this * customization's name. */ if (isIgnoreDescriptorItem(customization)) { /* * The user wants to ignore this descriptor item * so remove it from the descriptor's collection * of items. */ it.remove(); if (isFiner) { logger.log(Level.FINER, LogFacade.IGNORE_DESCRIPTOR, new Object[]{descriptorItemName, getName(descriptorItem)}); } } else { /* * The user wants to override the setting of this * descriptor item using the customized settings. */ String oldValue = getValue(descriptorItem); // for logging purposes only try { setDescriptorItemValue(descriptorItem, customization); if (isFiner) { logger.log(Level.FINER, LogFacade.OVERIDE_DESCRIPTOR, descriptorItemName + " " + getName(descriptorItem) + "=" + oldValue + " with " + toString(customization)); } } catch (Exception e) { logger.warning(toString(customization) + " " + e.getLocalizedMessage()); } } /* * We have matched this customization with a descriptor * item, so we can skip to the next customization. */ continue nextCustomization; } } /* * The customization matched no existing descriptor item, so * add a new descriptor item. */ try { T newItem = addDescriptorItem(customization); if (isFiner) { logger.log(Level.FINER, LogFacade.CREATE_DESCRIPTOR, descriptorItemName + getName(newItem) + "=" + getValue(newItem)); } } catch (Exception e) { logger.warning(toString(customization) + " " + e.getLocalizedMessage()); } } } } /** * Concrete implementation of the context-parameter customizer. */ private class ContextParamCustomizer extends Customizer { private ContextParamCustomizer(Set descriptorItems, List customizations) { super(descriptorItems, customizations, "context-param"); // NOI18N } @Override protected boolean isIgnoreDescriptorItem(ContextParam customization) { return Boolean.parseBoolean(customization.getIgnoreDescriptorItem()); } @Override protected void setDescriptorItemValue(ContextParameter descriptorItem, ContextParam customization) { descriptorItem.setValue(customization.getParamValue()); } @Override protected ContextParameter newDescriptorItem(ContextParam customization) { ContextParameter newItem = new EnvironmentProperty( customization.getParamName(), customization.getParamValue(), "" /* description */); return newItem; } @Override protected String getName(ContextParameter descriptorItem) { return descriptorItem.getName(); } @Override protected String getCustomizationName(ContextParam customization) { return customization.getParamName(); } @Override protected String getValue(ContextParameter descriptorItem) { return descriptorItem.getValue(); } @Override protected String toString(ContextParam customization) { return "Context-param: name=" + customization.getParamName() + ", value=" + customization.getParamValue(); } } /** * Concrete implementation for the EnvEntry customizer. */ private class EnvEntryCustomizer extends Customizer { private EnvEntryCustomizer(Set descriptorItems, List customizations) { super(descriptorItems, customizations, "env-entry"); // NOI18N } @Override protected boolean isIgnoreDescriptorItem(EnvEntry customization) { return Boolean.parseBoolean(customization.getIgnoreDescriptorItem()); } @Override protected void setDescriptorItemValue(EnvironmentEntry descriptorItem, EnvEntry customization) { customization.validateValue(); descriptorItem.setValue(customization.getEnvEntryValue()); descriptorItem.setType(customization.getEnvEntryType()); } @Override protected EnvironmentEntry newDescriptorItem(EnvEntry customization) { customization.validateValue(); EnvironmentEntry newItem = new EnvironmentProperty( customization.getEnvEntryName(), customization.getEnvEntryValue(), customization.getDescription(), customization.getEnvEntryType()); /* * Invoke setValue which records that the value has been set. * Otherwise naming does not bind the name. */ newItem.setValue(customization.getEnvEntryValue()); return newItem; } @Override protected String getName(EnvironmentEntry descriptorItem) { return descriptorItem.getName(); } @Override protected String getCustomizationName(EnvEntry customization) { return customization.getEnvEntryName(); } @Override protected String getValue(EnvironmentEntry descriptorItem) { return descriptorItem.getValue(); } @Override protected String toString(EnvEntry customization) { return "EnvEntry: name=" + customization.getEnvEntryName() + ", type=" + customization.getEnvEntryType() + ", value=" + customization.getEnvEntryValue() + ", desc=" + customization.getDescription(); } } private void stopCoherenceWeb() { if (wmInfo.getDescriptor() != null && wmInfo.getDescriptor().getSunDescriptor() != null) { SunWebAppImpl sunWebApp = (SunWebAppImpl) wmInfo.getDescriptor().getSunDescriptor(); if (sunWebApp.getSessionConfig() != null && sunWebApp.getSessionConfig().getSessionManager() != null) { SessionManager sessionManager = sunWebApp.getSessionConfig().getSessionManager(); String persistenceType = sessionManager.getAttributeValue( SessionManager.PERSISTENCE_TYPE); if (PersistenceType.COHERENCE_WEB.getType().equals(persistenceType)) { ClassLoader cloader = wmInfo.getAppClassLoader(); try { Class cacheFactoryClass = cloader.loadClass( "com.tangosol.net.CacheFactory"); if (cacheFactoryClass != null) { Method shutdownMethod = cacheFactoryClass.getMethod("shutdown"); if (shutdownMethod != null) { shutdownMethod.invoke(null); } } } catch(Exception ex) { if (logger.isLoggable(Level.WARNING)) { String msg = rb.getString(LogFacade.EXCEPTION_SHUTDOWN_COHERENCE_WEB); msg = MessageFormat.format(msg, wmInfo.getDescriptor().getName()); logger.log(Level.WARNING, msg, ex); } } } } } } }