/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.huihoo.jfox.service;

import javax.management.ObjectName;
import javax.management.MBeanServer;
import javax.management.Notification;
import javax.management.AttributeChangeNotification;

/**
 * 
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public abstract class ServiceSupport extends ComponentSupport implements ServiceSupportMBean {


  public ServiceSupport() {
    super();
  }

  public ServiceSupport(String name) {
    super(name);
  }

  public boolean isRunning() {
    return state == State.STARTED;
  }

  public void start() throws Exception {
    if(!State.canStart(state)) {
      logger.warn(name + " can not start, state = " + state);
      return;
    }


    logger.info("starting...");

    sendNotification(new AttributeChangeNotification(this,
                                                     sequence++,
                                                     System.currentTimeMillis(),
                                                     getName()+" starting",
                                                     "State",
                                                     "java.lang.Integer",
                                                     new Integer(state.getId()),
                                                     new Integer(State.STARTING.getId())));
    state = State.STARTING;

    try {
      doStart();
    }
    catch (Exception e) {
      sendNotification(new AttributeChangeNotification(this,
                                                       sequence++,
                                                       System.currentTimeMillis(),
                                                       getName()+" starting failed",
                                                       "State",
                                                       "java.lang.Integer",
                                                       new Integer(state.getId()), new Integer(State.INTERRUPTED.getId())));
      state = State.INTERRUPTED;
      logger.error("starting failed", e);
      throw e;
    }
    sendNotification(new AttributeChangeNotification(this,
                                                     sequence++,
                                                     System.currentTimeMillis(),
                                                     getName()+" started",
                                                     "State",
                                                     "java.lang.Integer",
                                                     new Integer(state.getId()),
                                                     new Integer(State.STARTED.getId())));
    state = State.STARTED;
    logger.info("started.");
  }

  public void stop() throws Exception {
    if(!State.canStop(state)) {
      logger.warn(name + " can not stop, state = " + state);
      return;
    }

    logger.info("stopping...");

    //AS It seems that the first attribute is not needed anymore and use a long instead of a Date
    sendNotification(new AttributeChangeNotification(this,
                                                     sequence++,
                                                     System.currentTimeMillis(),
                                                     getName()+" stopping",
                                                     "State",
                                                     "java.lang.Integer",
                                                     new Integer(state.getId()),
                                                     new Integer(State.STOPPING.getId())));
    state = State.STOPPING;

    try {
      doStop();
    }
    catch (Exception e) {
      sendNotification(new AttributeChangeNotification(this,
                                                       sequence++,
                                                       System.currentTimeMillis(),
                                                       getName()+" stopping failed",
                                                       "State",
                                                       "java.lang.Integer",
                                                       new Integer(state.getId()), new Integer(State.INTERRUPTED.getId())));
      state = State.INTERRUPTED;
      logger.error("stopping failed", e);
      throw e;
    }
    sendNotification(new AttributeChangeNotification(this,
                                                     sequence++,
                                                     System.currentTimeMillis(),
                                                     getName()+" stopped",
                                                     "State",
                                                     "java.lang.Integer",
                                                     new Integer(state.getId()),
                                                     new Integer(State.STOPPED.getId())));
    state = State.STOPPED;
    logger.info("stopped");

  }


  /**
   * ObjectName must specified in the MLet, or use registerMBean specified explicitly
   */
  public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
    if(name == null) throw new IllegalArgumentException("ObjectName can not be null.");

    // get log service instance
    this.server = server;
    objectName = name;

    return name;
  }

  public void postRegister(Boolean registrationDone) {
    if(!registrationDone.booleanValue()){
      try{
        this.stop(); this.destroy();
      }
      catch(Exception e){
        logger.error(e.getMessage(),e);
      }
    }
    else {
      // initilize & start
      try {
        this.init(); this.start();
      }
      catch(Exception e){
        logger.error(e.getMessage(),e);
      }

    }
  }

  public void preDeregister() throws Exception {

  }

  public void postDeregister() {
    try {
      stop();
    }
    catch(Exception e){
      e.printStackTrace();
    }

  }

  public void handleNotification(Notification notification, Object obj) {
    logger.info("Recieved notification, type: " + notification.getType() + ", " +
                 "message: " + notification.getMessage() + ", " +
                 "source: " + notification.getSource());
  }

  /**
   * do actually start action
   */
  protected abstract void doStart() throws Exception;
  /**
   * do actually stop action
   */
  protected abstract void doStop() throws Exception;

}
