/*
 * 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        "@(#)CIBExternalResource.java 1.33     04/07/15 SMI"
 *
 */

package com.sun.mfwk.cib;

import com.sun.mfwk.cib.CIBExternalResourceMBean;
import com.sun.mfwk.cib.CIBExternalResourceIf;
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.CIBExternalResourcePerfStats;
import com.sun.mfwk.cib.statistics.CIBStatistic;
import com.sun.mfwk.cib.config.CIBExternalResourceConfiguration;

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

import javax.management.ObjectName;

/**
 * Default implementation of a CIB External Resource MBean.
 */
public class CIBExternalResource
    extends CIBMonitoredObject
    implements CIBExternalResourceIf, CIBExternalResourceMBean {

  private ObjectName myApplication=null;
  protected ObjectName myServiceObjectName=null;
  private String myProviderUri;

  // the various providers for a CIBExternalService
  protected CIBExternalResourcePerfStats myExternalResourcePerfStatsProvider = null;
  protected CIBOperationalStatusState myOpStatusStateProvider = null;
  protected CIBAvailabilityStatusState myAvailStatusStateProvider = null;
  protected CIBExternalResourceConfiguration myExternalResourceConfigProvider = null;

  /**
   * Create a CIBExternalResource with the given providerUri
   * @param theProviderUri String
   */
  public CIBExternalResource(String theProviderUri) {
    myProviderUri = theProviderUri;
  }

  /**
   * Build a CIBExternalResource
   */
  public CIBExternalResource() {
  }

  // Retrieval of providers section

  /**
   *
   */
  protected void retrieveExternalResourceConfigProvider() throws CIBException {
    // CIBProviderHandler is supposed to be set
    try {

      if (myExternalResourceConfigProvider == null) {
        myExternalResourceConfigProvider =
            (CIBExternalResourceConfiguration) myProviderHandler.
            getConfiguration(this,
                             CIBProviderHandler.EXTERNALRESOURCE_CONFIG_TYPE);
      }
    }
    catch (Exception ex) {
      String message =
          " caught unexpected exception while retrieving External Resource Config provider";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(message, ex);
    }
  }

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

    try {
      // CIBProviderHandler is supposed to be set
      if (myExternalResourcePerfStatsProvider == null) {
        myExternalResourcePerfStatsProvider =
            (CIBExternalResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.EXTERNALRESOURCE_PERFSTATS_TYPE);
      }
    }
    catch (Exception ex) {
      String message = " caught unexpected exception while retrieving External Resource Perf Stats provider \n";
      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.EXTERNALRESOURCE_STATE_TYPE);
      }
    }
    catch (Exception ex) {
      String message = " caught unexpected exception while retrieving External Resource Operational MfStatus provider \n";
      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.
                                       EXTERNALRESOURCE_STATE_TYPE);
      }
    }
    catch (Exception ex) {
      String message = " caught unexpected exception while retrieving External Resource Availibility MfStatus provider\n ";
      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 {
      myAvailStatusStateProvider.init();
      myOpStatusStateProvider.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 {
    retrieveExternalServicePerfStatsProvider();
  }

  protected void initStatisticProviders() {
    try {
      myExternalResourcePerfStatsProvider.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 {
      myExternalResourcePerfStatsProvider.destroy();
      myExternalResourcePerfStatsProvider = null;
    }
    catch (CIBException ex) {
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                             " Caught CIBException " + ex +
                             " \n when trying to destroy statistic providers for : \n" +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
    }
  }

  // Configuration provider
  protected void retrieveConfigurationProviders() throws CIBException {
    retrieveExternalResourceConfigProvider();
  }

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

  protected void startConfigurationProviders() {
  }

  protected void stopConfigurationProviders() {
  }

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

  // Mediation interface
  /**
   * Allows to set the CIB Service Object Name
   */
  public void setCIBApplication(ObjectName objectName) {
    myApplication = objectName;
  }

  // MBean interface

  /**
   * Provides the Associated Service URI
   * @return String
   */

  public String getProviderUri() {
    if (myProviderUri != null) {
      return myProviderUri;
    }
    try {
      // systematic retrieval of perf stats to ensure uptodate data
      CIBExternalResourceConfiguration extResourceConfigProvider =
          (CIBExternalResourceConfiguration) myProviderHandler.getConfiguration(this,
          CIBProviderHandler.EXTERNALRESOURCE_CONFIG_TYPE);
      extResourceConfigProvider.init();
      return extResourceConfigProvider.getProviderUri();
    }
    catch (CIBException ex) {
      String message = " Caught unexpected exception " + ex;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      return null;
    }
  }

  /**
   *  Returns the name of the CIBApplication
   * @return ObjectName
   */
  public ObjectName getApplication() throws InvalidAttributeValueException {
    if (myApplication != null) {
      return myApplication;
    }
    else {
      String message = " Unset Application for External Resource : \n ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new InvalidAttributeValueException(message);
    }

  }

  /**
   * Returns the Stats object provided by the CIBProviderHandler
   * Gets a CIBStats object for all available statistics.
   * @return Stats
   */
  public Stats getStats() throws CIBException {
    try {
      if (!isCurrentlyProvidingStatistics) {
        return null;
      }
      else {
        // systematic retrieval of perf stats to ensure uptodate data
        CIBExternalResourcePerfStats externalServicePerfStatsProvider =
            (CIBExternalResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.EXTERNALRESOURCE_PERFSTATS_TYPE);
        externalServicePerfStatsProvider.init();
        return externalServicePerfStatsProvider;
      }
    }
    catch (CIBException ex) {
      String message = " Unexpected exception " + ex +
          " while calling getStats on External Resource : \n " +
          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 CIBException {
    if (!isCurrentlyProvidingStatistics) {
      return null;
    }
    try {
      // systematic retrieval of perf stats to ensure uptodate data
      CIBStatistic cibStatistic;
      CIBExternalResourcePerfStats externalServicePerfStatsProvider =
          (CIBExternalResourcePerfStats) myProviderHandler.getPerfStats(this,
          CIBProviderHandler.EXTERNALRESOURCE_PERFSTATS_TYPE);
      externalServicePerfStatsProvider.init();
      if ( (cibStatistic = (CIBStatistic) externalServicePerfStatsProvider.
            getStatistic(name)) != null) {
        return cibStatistic.toCompositeData();
      }
      else {
        String message = " Unexisting statistic " + name +
            " in External Resource : " + this.objectName;
        CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                               this +CIBMbeanNewLine +
                               CIBMbeanLogMessageClosingString);
        throw new CIBAttributeNotFoundException(message,
                                                " CIBExternalResourcePerfStats ",
                                                name);
      }
    }
    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 External 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;
        CIBExternalResourcePerfStats externalResourcePerfStatsProvider =
            (CIBExternalResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.EXTERNALRESOURCE_PERFSTATS_TYPE);
        externalResourcePerfStatsProvider.init();

        if (((statisticArray = externalResourcePerfStatsProvider.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)
                  externalResourcePerfStatsProvider.
                  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 External 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 {
    try {
      if (!isCurrentlyProvidingStatistics) {
        return null;
      }
      else {
        // systematic retrieval of perf stats to ensure uptodate data
        CIBExternalResourcePerfStats externalServicePerfStatsProvider =
            (CIBExternalResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.EXTERNALRESOURCE_PERFSTATS_TYPE);
        externalServicePerfStatsProvider.init();
        return externalServicePerfStatsProvider.toCompositeData();
      }
    }
    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
        CIBExternalResourcePerfStats externalServicePerfStatsProvider =
            (CIBExternalResourcePerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.EXTERNALRESOURCE_PERFSTATS_TYPE);
        externalServicePerfStatsProvider.init();
        return externalServicePerfStatsProvider.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 = -1;
      CIBOperationalStatusState opStatusProvider = myProviderHandler.
          getOperationalStatusState(this,
                                    CIBProviderHandler.
                                    EXTERNALRESOURCE_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.
                                    EXTERNALRESOURCE_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.
                                    EXTERNALRESOURCE_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 availProvider =
          myProviderHandler.getAvailabilityStatusState(
            this,
            CIBProviderHandler.EXTERNALRESOURCE_STATE_TYPE);
      availProvider.init();
      result = availProvider.getState();
      if ((result != availStatus) &&
          (isEventProvider())) {
        eventBroadcaster.sendNotification(
          new AttributeChangeNotification(this, eventNumber++, System.currentTimeMillis(), null,
                                          "AvailibityStatusState", "int",
                                          new Integer(opStatus), 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 availProvider =
          myProviderHandler.getAvailabilityStatusState(this,
          CIBProviderHandler.EXTERNALRESOURCE_STATE_TYPE);
      availProvider.init();
      return availProvider.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 availProvider =
          myProviderHandler.getAvailabilityStatusState(this,
          CIBProviderHandler.EXTERNALRESOURCE_STATE_TYPE);
      availProvider.init();
      return availProvider.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);
    }
  }
  /**
   * getService
   *
   * @return ObjectName
   */
  public ObjectName getService() {
    return myServiceObjectName;
  }

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

}
