/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2005-2007 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.web.tomcat6;

import java.net.URL;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.ContextEnvironment;
import org.apache.catalina.deploy.ContextResource;
import org.apache.catalina.deploy.MessageDestinationRef;
import org.apache.tomcat.util.modeler.Registry;

import org.ow2.jonas.deployment.web.WebContainerDeploymentDesc;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;


/**
 * Define a JOnAS context. It is used to check if a context has been defined in
 * server.xml and to use this context while deploying the war instead of
 * creating a new one
 * @author Florent Benoit
 * @author Philippe Coq (Tomcat 4.0)
 */
public final class JOnASStandardContext extends StandardContext {

    /**
     * UID for the serialization.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Unique instance of Catalina.
     */
    private static transient Tomcat6Service catalinaService = null;

    /**
     * Logger for this service.
     */
    private static Log logger = LogFactory.getLog(JOnASStandardContext.class);

    /**
     * URL of the ear.
     */
    private URL earURL = null;

    /**
     * We are in ear case or not ?
     */
    private boolean inEarCase = false;

    /**
     * This context was configured in server.xml ?
     */
    private boolean inServerXml = false;

    /**
     * Java 2 delegation model is use or not ?
     */
    private boolean java2DelegationModel = false;

    /**
     * WEB deployment descriptor.
     */
    private WebContainerDeploymentDesc webDeploymentDescriptor = null;

    /**
     * JOnAS deployment descriptor.
     */
    private String jonasDeploymentDescriptor = null;

    /**
     * Context was started ?
     */
    private boolean startedJStdx = false;

    /**
     * URL of the war.
     */
    private URL warURL = null;

    /**
     * J2EEApplication MBean OBJECT_NAME in ear case.
     */
    private String earON = null;

    /**
     * Constructor of the Context.
     */
    public JOnASStandardContext() {
        this(true, true, false);
    }

    /**
     * Constructor of the Context.
     * @param inServerXml this context was defined in server.xml
     * @param java2DelegationModel delegation model for classloader is true ?
     * @param inEarCase if we are or not in EAR case
     */
    public JOnASStandardContext(final boolean inServerXml, final boolean java2DelegationModel, final boolean inEarCase) {
        super();
        this.inServerXml = inServerXml;
        this.java2DelegationModel = java2DelegationModel;
        this.inEarCase = inEarCase;
    }

    /**
     * Assign the parent Tomcat6 WebContainerService.
     * @param tomcat {@link Tomcat6Service} instance.
     */
    public void setTomcatService(final Tomcat6Service tomcat) {
        catalinaService = tomcat;
    }

    /**
     * @return Returns the earURL.
     */
    public URL getEarURL() {
        return earURL;
    }

    /**
     * Gets the web deployment descriptor content.
     * @return the content of the web deployment descriptor
     */
    public WebContainerDeploymentDesc getWebDeploymentDescriptor() {
        return webDeploymentDescriptor;
    }

    /**
     * Gets the deployment descriptor content of jonas-web.xml file.
     * @return the content of jonas-web.xml file
     */
    public String getJonasDeploymentDescriptor() {
        return jonasDeploymentDescriptor;
    }

    /**
     * @return Returns the warURL.
     */
    public URL getWarURL() {
        return warURL;
    }

    /**
     * @return true if this web module is a part of a EAR
     */
    public boolean isInEarCase() {
        return inEarCase;
    }

    /**
     * This context was defined in server.xml ?
     * @return true if this context was defined in server.xml
     */
    public boolean isInServerXml() {
        return inServerXml;
    }

    /**
     * @return true if the Java2 delegation model is used
     */
    public boolean isJava2DelegationModel() {
        return java2DelegationModel;
    }

    /**
     * @param earURL The earURL to set.
     */
    protected void setEarURL(final URL earURL) {
        this.earURL = earURL;
        // Determine the corresponding J2EEApplication ObjectName
        ObjectName j2eeAppOn = null;
        // Catalina StandardContext provides setter and getter for
        // j2eeApplication attribute
        // The setter was called in
        // CatalinaJWebContainerServiceImpl.doRegisterWar method
        // befor the call to this setter
        String appName = getJ2EEApplication();
        // setServer() was called before this setter
        String serverON = getServer();
        if (appName != null && serverON != null) {
            ObjectName serverOn;
            try {
                serverOn = ObjectName.getInstance(serverON);
                String domainName = serverOn.getDomain();
                String serverName = serverOn.getKeyProperty("name");
                j2eeAppOn = J2eeObjectName.J2EEApplication(domainName, serverName, appName);
            } catch (MalformedObjectNameException e) {
                logger.error("Cannot build the ObjectName for the context ''{0}''", e);
            }
        }
        if (j2eeAppOn != null) {
            earON = j2eeAppOn.toString();
        }
    }

    /**
     * @param inEarCase The inEarCase to set.
     */
    protected void setInEarCase(final boolean inEarCase) {
        this.inEarCase = inEarCase;
    }

    /**
     * @param java2DelegationModel The java2DelegationModel to set.
     */
    protected void setJava2DelegationModel(final boolean java2DelegationModel) {
        this.java2DelegationModel = java2DelegationModel;
    }

    /**
     * Set the web deployment descriptor content.
     * @param jonasDeploymentDescriptor the content of the web deployment descriptor
     */
    public void setWebDeploymentDescriptor(final WebContainerDeploymentDesc webDeploymentDescriptor) {
        this.webDeploymentDescriptor = webDeploymentDescriptor;
    }

    /**
     * Set the deployment descriptor content of jonas-web.xml file.
     * @param jonasDeploymentDescriptor the content of jonas-web.xml
     */
    public void setJonasDeploymentDescriptor(final String jonasDeploymentDescriptor) {
        this.jonasDeploymentDescriptor = jonasDeploymentDescriptor;
    }

    /**
     * @param warURL The warURL to set.
     */
    protected void setWarURL(final URL warURL) {
        this.warURL = warURL;
    }

    /**
     * Start the JOnAS context if catalina is started.
     * @throws LifecycleException if the context can't be started
     */
    @Override
    public synchronized void start() throws LifecycleException {
        if (catalinaService != null && catalinaService.isTomcatStarted()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Tomcat in Web container service is started, starting the context...");
            }
            startedJStdx = true;
            super.start();
        }

    }

    /**
     * Stop this Context component.
     * @exception LifecycleException if a shutdown error occurs
     */
    @Override
    public synchronized void stop() throws LifecycleException {
        if (startedJStdx) {
            startedJStdx = false;
            super.stop();
            unregisterJMX();
        }

    }

    /**
     * Unregister the WebModule MBean of this Context.
     */
    private void unregisterJMX() {
        // Bug Tomcat 5/6 doesn't remove MBean WebModule
        // Delete the next line when will be fixed
        if(getObjectName() != null) {
            Registry.getRegistry(null, null).unregisterComponent(getObjectName());
            // TODO broadcast the "j2ee.object.deleted" notification
        }

    }

    /**
     * Add a resource reference for this web application. Do nothing when
     * running inside JOnAS. Resources are managed by JOnAS
     * @param resource New resource reference
     */
    public void addResource(final ContextResource resource) {
    }

    /**
     * Add an environment entry for this web application. Do nothing when
     * running inside JOnAS. ENC environment is managed by JOnAS
     * @param environment New environment entry
     */
    public void addEnvironment(final ContextEnvironment environment) {
    }

    /**
     * Add a message destination reference for this web application.  Do nothing when
     * running inside JOnAS. Resources are managed by JOnAS
     * @param mdr New message destination reference
     */
    public void addMessageDestinationRef(final MessageDestinationRef mdr) {

    }

    /**
     * Set the parent class loader for this web application. Do it only if it is
     * not started.
     * @param parent The new parent class loader
     */
    @Override
    public void setParentClassLoader(final ClassLoader parent) {
        // Do it only if the context is not already started
        if (!startedJStdx) {
            super.setParentClassLoader(parent);
        }
    }

    /**
     * @return OBJECT_NAME of the parent J2EEApplication MBean
     */
    public String getEarON() {
        return earON;
    }

}
