/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 *
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits réservés.
 * Ce logiciel est propriété de Sun Microsystems, Inc.
 * Distribué par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)CIBResource.java 1.32     04/07/15 SMI"
 *
 */

package com.sun.mfwk.cib;

import com.sun.mfwk.cib.CIBResourceMBean;
import com.sun.mfwk.cib.CIBResourceIf;
import com.sun.mfwk.cib.CIBMonitoredObject;
import com.sun.mfwk.cib.providers.CIBProviderHandler;

import com.sun.mfwk.cib.states.CIBOperationalStatusState;
import com.sun.mfwk.cib.states.CIBAvailabilityStatusState;
import com.sun.mfwk.cib.statistics.CIBResourcePerfStats;
import com.sun.mfwk.cib.statistics.CIBStatistic;

import javax.management.openmbean.CompositeData;
import javax.management.j2ee.statistics.Stats;
import javax.management.openmbean.OpenDataException;
import javax.management.InvalidAttributeValueException;
import javax.management.AttributeChangeNotification;

import javax.management.ObjectName;
import javax.management.j2ee.statistics.Stats;
import javax.management.j2ee.statistics.Statistic;
import javax.management.openmbean.*;

/**
 * Default implementation of a CIB Resource MBean.
 */
public class CIBResource
    extends CIBMonitoredObject
    implements CIBResourceIf, CIBResourceMBean {

  ObjectName myApplication = null;
  ObjectName myService = null;

  // the various providers for a CIBService
  protected CIBResourcePerfStats myResourcePerfStatsProvider = null;
  protected CIBOperationalStatusState myOpStatusStateProvider = null;
  protected CIBAvailabilityStatusState myAvailStatusStateProvider = null;

  public CIBResource() {
  }

  // Retrieval of providers section

  /**
   *
   */
  protected void retrieveResourcePerfStatsProvider() throws CIBException {

    try {
      // CIBProviderHandler is supposed to be set
      if (myResourcePerfStatsProvider == null) {
        myResourcePerfStatsProvider =
            (CIBResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.RESOURCE_PERFSTATS_TYPE);
      }
    }
    catch (Exception ex) {
      String message =
          " caught unexpected exception while retrieving Resource Perf Stats provider";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(message, ex);
    }
  }

  protected void retrieveOpStatusStateProvider() throws CIBException {

    try {
      // CIBProviderHandler is supposed to be set
      if (myOpStatusStateProvider == null) {
        myOpStatusStateProvider = myProviderHandler.getOperationalStatusState(this,
            CIBProviderHandler.RESOURCE_STATE_TYPE);
      }
    }
    catch (Exception ex) {
      String message = " caught unexpected exception while retrieving Resource Operational MfStatus provider";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(message, ex);
    }
  }

  protected void retrieveAvailStatusStateProvider() throws CIBException {

    try {
      // CIBProviderHandler is supposed to be set
      if (myAvailStatusStateProvider == null) {
        myAvailStatusStateProvider = myProviderHandler.
            getAvailabilityStatusState(this,
                                       CIBProviderHandler.RESOURCE_STATE_TYPE);
      }
    }
    catch (Exception ex) {
      String message = " caught unexpected exception while retrieving Resource Availibility MfStatus provider";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(message, ex);
    }
  }

  // from abstract superclass CIBMonitoredObject
  protected void retrieveStateProviders() throws CIBException {
    retrieveOpStatusStateProvider();
    retrieveAvailStatusStateProvider();
  }

  protected void initStateProviders() {
    try {
      myOpStatusStateProvider.init();
      myAvailStatusStateProvider.init();
    }
    catch (CIBException ex) {
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                             " Caught CIBException " + ex +
                             " \n when trying to init state providers for : \n" +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
    }
  }

  protected void startStateProviders() {
  }

  protected void stopStateProviders() {
  }

  protected void destroyStateProviders() {
    try {
      myAvailStatusStateProvider.destroy();
      myAvailStatusStateProvider = null;
      myOpStatusStateProvider.destroy();
      myOpStatusStateProvider = null;
    }
    catch (CIBException ex) {
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                             " Caught CIBException " + ex +
                             " \n when trying to destroy state providers for : \n" +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
    }
  }

  protected void retrieveStatisticProviders() throws CIBException {
    retrieveResourcePerfStatsProvider();
  }

  protected void initStatisticProviders() {
    try {
      myResourcePerfStatsProvider.init();
    }
    catch (CIBException ex) {
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                             " Caught CIBException " + ex +
                             " \n when trying to init statistic providers for : \n" +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
    }
  }

  protected void startStatisticProviders() {
  }

  protected void stopStatisticProviders() {
  }

  protected void destroyStatisticProviders() {
    try {
      myResourcePerfStatsProvider.destroy();
      myResourcePerfStatsProvider = null;
    }
    catch (CIBException ex) {
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                             " Caught CIBException " + ex +
                             " \n when trying to destroy statistic providers for : \n" +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
    }
  }

  // Mediation interface

  /**
   * Allows to set the CIBApplication object name
   * @param objectName ObjectName
   */
  public void setCIBApplication(ObjectName objectName) {
    myApplication = objectName;
  }

  /**
   * Allows to set the CIBService object name
   * @param objectName ObjectName
   */
  public void setCIBService(ObjectName objectName) {
    myService = objectName;
  }

  // Mbean interface


  /**
   *  Returns the name of the CIBApplication
   * @return javax.management.ObjectName
   */
  public ObjectName getApplication() {
    return myApplication;
  }

  /**
   *  Returns the name of the CIBApplication
   * @return javax.management.ObjectName
   */
  public ObjectName getService() {
    return myService;
  }

  /**
   * Returns the Stats object provided by the CIBProviderHandler
   * Gets a CIBStats object for all available statistics.
   * @return Stats
   */
  public Stats getStats() throws CIBException {
    if (!isCurrentlyProvidingStatistics) {
      return null;
    }
    else {
      try {

        // systematic retrieval of perf stats to ensure uptodate data
        CIBResourcePerfStats resourcePerfStatsProvider = null;
        resourcePerfStatsProvider =
            (CIBResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.RESOURCE_PERFSTATS_TYPE);
        resourcePerfStatsProvider.init();
        return resourcePerfStatsProvider;
      }
      catch (CIBException ex) {
        String message = " Unexpected exception " + ex +
            " while calling getStats on Resource : " + this.objectName;
        CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                               message + this +CIBMbeanNewLine +
                               CIBMbeanLogMessageClosingString);
        throw ex;
      }
    }
  }

  /**
   * Gets a CIB Statistic as a standard serializable JMX Open Type
   *
   * @param name String
   * @return CompositeData
   */
  public CompositeData getOpenStatistic(String name) throws
      CIBAttributeNotFoundException, CIBException {
    if (!isCurrentlyProvidingStatistics) {
      return null;
    }
    else {
      try {
        // systematic retrieval of perf stats to ensure uptodate data
        CIBStatistic cibStatistic;
        CIBResourcePerfStats resourcePerfStatsProvider = null;

        resourcePerfStatsProvider =
            (CIBResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.RESOURCE_PERFSTATS_TYPE);

        resourcePerfStatsProvider.init();
        if ( (cibStatistic = (CIBStatistic) resourcePerfStatsProvider.
              getStatistic(name)) != null) {
          return cibStatistic.toCompositeData();
        }
        else {
          return null;
        }
      }
      catch (Exception e) {
        if (e instanceof OpenDataException) {
          String message = " Caught unexpected OpenType exception " + e;
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
          throw new CIBException(message, e);
        }
        else {
          String message = " caught unexpected exception : \n" + e +
              "\n in Resource : \n " + this.objectName;
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
          throw new CIBException(message, e);
        }
      }
    }
  }

  /**
   *  Gets all CIBStatistics encoded as serializable JMX Open Types.
   *  If no statistics is found null is returned.
   *
   * @param names String[]
   * @return CompositeData[]
   */
  public CompositeData[] getOpenStatistics(String[] names) throws CIBException {
    if (!isCurrentlyProvidingStatistics) {
      return null;
    }
    else {
      try {
        // systematic retrieval of perf stats to ensure uptodate data
        Statistic[] statisticArray = null;
        int nb_names = names.length;
        CIBResourcePerfStats resourcePerfStatsProvider = null;

        resourcePerfStatsProvider =
            (CIBResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.RESOURCE_PERFSTATS_TYPE);

        resourcePerfStatsProvider.init();

        if (((statisticArray = resourcePerfStatsProvider.getStatistics()) == null) ||
             (statisticArray.length == 0)) {
          return null;
        }
        else {
          CompositeData[] openStatistics = new CompositeData[nb_names];
          for (int i = nb_names - 1; i >= 0; i--) {
            try {
              CIBStatistic stat = (CIBStatistic) resourcePerfStatsProvider.
                  getStatistic(names[i]);
              if (stat == null) {
                openStatistics[i] = null;
              }
              else {
                openStatistics[i] = stat.toCompositeData();
              }
            }
            catch (Exception e) {
              CIBMbeanLogger.info(CIBMbeanLogMessageHeaderString +
                                  "exception while retrieving statistic named : " +
                                  names[i] +
                                  "in perfstats provider for Resource : \n" +
                                  this +CIBMbeanNewLine +
                                  CIBMbeanLogMessageClosingString);
              openStatistics[i] = null;
            }
          }
          return openStatistics;
        }
      }
      catch (Exception e) {
        if (e instanceof OpenDataException) {
          String message = " Caught unexpected OpenType exception " + e;
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
        }
        throw new CIBException(e);
      }
    }
  }

  /**
   * Gets a CIBStats object encoded as a standard serializable JMX Open Type
   *
   * @return javax.management.openmbean.CompositeData
   */
  public CompositeData getOpenStats() throws CIBException {
    if (!isCurrentlyProvidingStatistics) {
      return null;
    }
    else {
      try {
        CompositeData data = null;
        // systematic retrieval of perf stats to ensure uptodate data
        CIBResourcePerfStats resourcePerfStatsProvider = null;
        resourcePerfStatsProvider =
            (CIBResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.RESOURCE_PERFSTATS_TYPE);
        resourcePerfStatsProvider.init();
        data = resourcePerfStatsProvider.toCompositeData();
        return data;
      }
      catch (Exception ex) {
        if (ex instanceof OpenDataException) {
          String message = " Caught unexpected OpenType exception " + ex;
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
        }
        throw new CIBException(ex);
      }
    }
  }

  /**
   * Gets all available statistic names
   *
   * @return String[]
   */
  public String[] getStatisticNames() throws CIBException {
    try {
      if (!isCurrentlyProvidingStatistics) {
        return null;
      }
      else {
        // systematic retrieval of perf stats to ensure uptodate data
        CIBResourcePerfStats resourcePerfStatsProvider = null;
        resourcePerfStatsProvider =
            (CIBResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.RESOURCE_PERFSTATS_TYPE);
        resourcePerfStatsProvider.init();
        return resourcePerfStatsProvider.getStatisticNames();
      }
    }
    catch (Exception ex) {
      throw new CIBException(" Caught unexpected exception ", ex);
    }
  }

  /**
   * Get the Operational MfStatus of the monitored object
   * @return int
   */
  public int getOperationalStatusState() throws CIBException {
    if (!isCurrentlyProvidingState) {
      return -1;
    }

    try {
      int result;
      CIBOperationalStatusState opStatusProvider = myProviderHandler.
          getOperationalStatusState(this,
                                    CIBProviderHandler.RESOURCE_STATE_TYPE);
      opStatusProvider.init();
      result = opStatusProvider.getState();
      if ((result != opStatus) &&
          (isEventProvider())) {
        eventBroadcaster.sendNotification(
          new AttributeChangeNotification(this, eventNumber++, System.currentTimeMillis(), null,
                                          "OperationalStatusState", "int",
                                          new Integer(opStatus), new Integer(result)));
      }
      opStatus = result;
      return opStatus;
    }
    catch (CIBIOException ex) {
      String message =
          " caught IO exception in CIB SDK while calling getOperationalStatusState ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(
          " unexpected IO exception in CIB SDK implemetation", ex);
    }
  }

  /**
   * Get the time when the operational status last changed
   * @return long
   */
  public long getOperationalStatusLastChange() throws CIBException {
    if (!isCurrentlyProvidingState) {
      return -1;
    }

    try {
      CIBOperationalStatusState opStatusProvider = myProviderHandler.
          getOperationalStatusState(this,
                                    CIBProviderHandler.RESOURCE_STATE_TYPE);
      opStatusProvider.init();
      return opStatusProvider.getLastChange();
    }
    catch (CIBIOException ex) {
      String message =
          " caught IO exception in CIB SDK while calling getOperationalStatusLastChange ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(
          " unexpected IO exception in CIB SDK implemetation", ex);
    }
  }

  /**
   * Get the time when the Operational status entered into the running state
   * @return long
   */

  public long getOperationalStatusStartTime() throws CIBException {
    if (!isCurrentlyProvidingState) {
      return -1;
    }

    try {
      CIBOperationalStatusState opStatusProvider = myProviderHandler.
          getOperationalStatusState(this,
                                    CIBProviderHandler.RESOURCE_STATE_TYPE);
      opStatusProvider.init();
      return opStatusProvider.getStartTime();
    }
    catch (CIBIOException ex) {
      String message =
          " caught IO exception in CIB SDK while calling getOperationalStatusStartTime ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(
          " unexpected IO exception in CIB SDK implementation", ex);
    }
  }

  /**
   * Get the Availability State of the Monitored object
   * @return int
   */
  public int getAvailabilityStatusState() throws CIBException {
    if (!isCurrentlyProvidingState) {
      return -1;
    }

    try {
      int result;
      CIBAvailabilityStatusState availStatusProvider =
          myProviderHandler.getAvailabilityStatusState(this,
          CIBProviderHandler.RESOURCE_STATE_TYPE);
      availStatusProvider.init();
      result = availStatusProvider.getState();
      if ((result != availStatus) &&
          (isEventProvider())) {
        eventBroadcaster.sendNotification(
          new AttributeChangeNotification(this, eventNumber++, System.currentTimeMillis(), null,
                                          "AvailibilityStatusState", "int",
                                          new Integer(availStatus), new Integer(result)));
      }
      availStatus = result;
      return availStatus;
    }
    catch (CIBIOException ex) {
      String message =
          " caught IO exception in CIB SDK while calling getOperationalStatusState ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(
          " unexpected IO exception in CIB SDK implementation", ex);
    }
  }

  /**
   * Get the time when the availability status last changed
   * @return long
   */
  public long getAvailabilityStatusLastChange() throws CIBException {
    if (!isCurrentlyProvidingState) {
      return -1;
    }
    try {
      CIBAvailabilityStatusState availStatusProvider =
          myProviderHandler.getAvailabilityStatusState(this,
          CIBProviderHandler.RESOURCE_STATE_TYPE);
      availStatusProvider.init();
      return availStatusProvider.getLastChange();
    }
    catch (CIBIOException ex) {
      String message =
          " caught IO exception in CIB SDK while calling getAvailibilityStatusLastChange ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(
          " unexpected IO exception in CIB SDK implementation", ex);
    }
  }

  /**
   * Returns the time the first time the object entered into the degraded state
   * @return long
   */

  public long getAvailabilityStatusDegradedTime() throws CIBException {
    if (!isCurrentlyProvidingState) {
      return -1;
    }
    try {
      CIBAvailabilityStatusState availStatusProvider =
          myProviderHandler.getAvailabilityStatusState(this,
          CIBProviderHandler.RESOURCE_STATE_TYPE);
      availStatusProvider.init();
      return availStatusProvider.getDegradedTime();
    }
    catch (CIBIOException ex) {
      String message = " caught IO exception in CIB SDK while calling getAvailibilityStatusDegradedTime ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(
          " unexpected IO exception in CIB SDK implementation", ex);
    }
  }

  /**
   * retrieveConfigurationProviders
   */
  protected void retrieveConfigurationProviders() {
  }

  /**
   * initConfigurationProviders
   */
  protected void initConfigurationProviders() {
  }

  /**
   * startConfigurationProviders
   */
  protected void startConfigurationProviders() {
  }

  /**
   * stopConfigurationProviders
   */
  protected void stopConfigurationProviders() {
  }

  /**
   * destroyConfigurationProviders
   */
  protected void destroyConfigurationProviders() {
  }

}

