/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (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/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */

package com.sun.enterprise.management.model;

import java.util.*;
import javax.management.*;

import com.sun.enterprise.management.util.J2EEModuleCallBack;

public abstract class J2EEDeployedObjectMdl extends J2EEEventProviderMOMdl {

    public static final int STARTING_STATE = 0;
    public static final int RUNNING_STATE = 1;
    public static final int STOPPING_STATE = 2;
    public static final int STOPPED_STATE = 3;
    public static final int FAILED_STATE = 4;

    private J2EEModuleCallBack module;
    private int state = this.RUNNING_STATE;
    private long startTime = System.currentTimeMillis();
    
    private long sequenceNo = 0;
    
    //private com.sun.enterprise.tools.deployment.backend.DeploymentContext userData = null;

    private String [] eventTypes = new String [] {"j2ee.state.starting","j2ee.state.running","j2ee.state.stopping","j2ee.state.stopped","j2ee.state.failed"};

    J2EEDeployedObjectMdl(J2EEModuleCallBack m) {
	super(m.getName(), m.getServerName(), false, false);
	module = m;
    }

    /**
    * The deploymentDescriptor string must contain the original XML deployment descriptor that was created for this module during the deployment process. 
    */ 
    public String getdeploymentDescriptor() {
        return module.getDeploymentDescriptor();
    }

    /** returns the OBJECT_NAME of the J2EEServer this module is deployed on. */
    public String getserver() {
        String qs = "name=" + getJ2EEServer() + ",j2eeType=J2EEServer";
        Set s = findNames(qs);
        ObjectName[] sa = (ObjectName[]) s.toArray(
            new ObjectName[s.size()]);
        if (sa.length > 0) {
            return sa[0].toString();
        }
        return "Failed to find the server ObjectName";
    }

    public String[] geteventTypes(){
        return eventTypes;
    }

    public int getstate(){
        return this.state;
    }

    public void setstate(int st){
        this.state = st;
        this.stateChanged(eventTypes[st]);
    }
    
    public long getstartTime(){
        return this.startTime;
    }
    public void start() {

	if ((this.state == this.STARTING_STATE) ||
	    (this.state == this.RUNNING_STATE) ||
	    (this.state == this.STOPPING_STATE)) {
            throw new RuntimeException(
		  new Exception ("cannot start because the current state is " + this.state));
	}

        try{
            this.state = this.STARTING_STATE;
            this.stateChanged("j2ee.state.starting");
	    module.start(this);
            this.state = this.RUNNING_STATE;
            this.startTime = System.currentTimeMillis();
            this.stateChanged("j2ee.state.running");
        }catch(Exception ex){
            this.state = this.FAILED_STATE;
            this.stateChanged("j2ee.state.failed");
	    if(ex instanceof RuntimeException)
                throw (RuntimeException)ex;
            throw new RuntimeException(ex);
        }
    }

    public void stop() throws MBeanException {

	if ((this.state == this.STOPPED_STATE) ||
	    (this.state == this.STOPPING_STATE)) {
            throw new RuntimeException(
		new Exception("cannot stop because the current state is " + this.state));
	}

        try{
            this.state = this.STOPPING_STATE;
            this.stateChanged("j2ee.state.stopping");
	    module.stop(this);
            this.state = this.STOPPED_STATE;
            this.stateChanged("j2ee.state.stopped");
        }catch(Exception ex){
            this.state = this.FAILED_STATE;
            this.stateChanged("j2ee.state.failed");
	    if(ex instanceof RuntimeException)
                throw (RuntimeException)ex;
            throw new RuntimeException(ex);
        }
    }

    public void startRecursive() throws MBeanException {
        start();
    }

    private void stateChanged(String state){
        /*
        Called when this MBean is not yet registered (see below).
        Since nothing should be listening to an MBean that is not yet registered, just
        skip the Notification.  If there were listeners, 'this' could be used as the
        source object; it needn't be an ObjectName.
        
        com.sun.enterprise.management.util.J2EEManagementObjectManager.setState(J2EEManagementObjectManager.java:1550)
        com.sun.enterprise.management.util.J2EEManagementObjectManager.setApplicationState(J2EEManagementObjectManager.java:1498)
        com.sun.enterprise.server.ApplicationLoader.setState(ApplicationLoader.java:395)
        com.sun.enterprise.server.AbstractManager.load(AbstractManager.java:211)
        com.sun.enterprise.server.ApplicationLifecycle.onStartup(ApplicationLifecycle.java:204)
        com.sun.enterprise.server.ApplicationServer.onStartup(ApplicationServer.java:326)
        com.sun.enterprise.server.ondemand.OnDemandServer.onStartup(OnDemandServer.java:112)
        com.sun.enterprise.server.PEMain.run(PEMain.java:326)
        com.sun.enterprise.server.PEMain.main(PEMain.java:260)
    */
        final ObjectName objectName    = getObjectName();
        if ( objectName != null )
        {
            Notification notification   = null;
            synchronized (this) // thread safety, visibility of 'sequenceNo'
            {
                notification = new Notification( state, objectName, sequenceNo);
                ++sequenceNo;
            }
            this.sendNotification( notification );
        }
    }
    
    /** Getter for property userData.
     * @return Value of property userData.
     */
    //public com.sun.enterprise.tools.deployment.backend.DeploymentContext getUserData() {
        //return userData;
    //}    
    
    /** Setter for property userData.
     * @param userData New value of property userData.
     */
    //public void setUserData(com.sun.enterprise.tools.deployment.backend.DeploymentContext userData) {
        //this.userData = userData;
    //}   
}
