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

package com.sun.mfwk.cib;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;

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.CIBApplicationPerfStats;
import com.sun.mfwk.cib.statistics.CIBStatistic;
import com.sun.mfwk.cib.config.CIBConfiguration;
import com.sun.mfwk.cib.config.CIBApplicationConfiguration;
import com.sun.mfwk.util.log.MfLogService;

import javax.management.openmbean.CompositeData;
import javax.management.openmbean.OpenDataException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.AttributeChangeNotification;
import javax.management.Attribute;

import javax.management.j2ee.statistics.Stats;
import javax.management.j2ee.statistics.Statistic;

import javax.management.ObjectName;

/**
 * Default implementation of a CIB Application.
 */
public class CIBApplication
    extends CIBMonitoredObject
    implements CIBApplicationMBean, CIBApplicationIf {

  // Core information base relations
  private Set myServicesSet = new HashSet();
  private Set myExternalResourcesSet = new HashSet();
  private Set myResourcesSet = new HashSet();
  private Set myApplicationsSet = new HashSet();

  // properties
  private ObjectName myProduct = null;
  private ObjectName myContainer = null;
  private String myRole = null;
  private String myUrlDescription = null;
  private String myDirectoryDN = null;

  // state and stats (statistic providers)
  // these variables only used for
  protected CIBApplicationPerfStats myApplicationPerfStatsProvider = null;
  protected CIBOperationalStatusState myOpStatusStateProvider = null;
  protected CIBAvailabilityStatusState myAvailStatusStateProvider = null;
  protected CIBApplicationConfiguration myApplicationConfigProvider = null;

  /**
   * @label consumedResources
   * @clientCardinality 1
   * @supplierCardinality 0..* 
   */
  private CIBResource lnkCIBResource1;

  /**
   * @label deployedServices
   * @clientCardinality 1
   * @supplierCardinality 1..* 
   */
  private CIBService lnkCIBService;

  /**
   * @label consumedServices
   * @clientCardinality 1
   * @supplierCardinality 0..* 
   */
  private CIBExternalResource lnkCIBExternalResource;

  /**
   * @label containedApplications
   * @supplierCardinality 0..*
   * @clientCardinality 1 
   */
  private CIBApplication lnkCIBApplication;

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

  /**
   * Build a CIBApplication the given configuration parameters
   * @param role String
   * @param urlDescription String
   * @param directoryDN String
   */

  public CIBApplication(String role, String urlDescription, String directoryDN) {
    myUrlDescription = urlDescription;
    myRole = role;
    myDirectoryDN = directoryDN;
  }

  // Retrieval of providers section

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

      if (myApplicationPerfStatsProvider == null) {
        myApplicationPerfStatsProvider =
            (CIBApplicationPerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.APPLICATION_PERFSTATS_TYPE);
      }
    }
    catch (Exception ex) {
      String message =
          " caught unexpected exception while retrieving Service Perf Stats provider";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new CIBException(message, ex);
    }
  }

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

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

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

  protected void retrieveAvailStatusStateProvider() throws CIBException {
    // CIBProviderHandler is supposed to be set
    try {
      if (myAvailStatusStateProvider == null) {
        myAvailStatusStateProvider = myProviderHandler.
            getAvailabilityStatusState(this,
                                       CIBProviderHandler.
                                       APPLICATION_STATE_TYPE);
      }
    }
    catch (Exception ex) {
      String message = " caught unexpected exception while retrieving Service 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 {
      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 {
    retrieveApplicationPerfStatsProvider();
  }

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

  /**
   * Set the stateProvider to val
   * @param val boolean
   * @throws CIBException
   */
  public void setStateProvider(boolean val) throws CIBException {

      if (!isRegistered) {
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                 "Impossible to enable/disable monitoring on connected servcies and resources !\n" +
                                 " CIBApplication " + objectName + "is unregistered, undefined mbeanserver " +
                                 CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
          throw new CIBException("Unregistered CIBApplication, cannot call setStateProvider on linked monitored objects");
      }
      else {
          // first propagate the enabling/disabling to connected resources and services
          ObjectName tmpOn;
          Boolean tmpBool = new Boolean(val);

          // enable/disable monitoring on all services first
          for (Iterator j = myServicesSet.iterator(); j.hasNext(); ) {
              tmpOn = (ObjectName) j.next();
              try {
                  mbeanServer.setAttribute(tmpOn, new Attribute("StateProvider", tmpBool));
              }
              catch (Exception e) {
                  CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                         "Caught exception : " + e +
                                         "\n while invoking setStateProvider method on CIB service named :\n" +
                                         tmpOn +
                                         " from CIB Application named :\n " + objectName +
                                         CIBMbeanNewLine +
                                         CIBMbeanLogMessageClosingString);
                  throw new CIBException("Exception in CIBApplication while invoking setStateProvider on a linked service" , e);
              }
          }

          // enable/disable monitoring on all resources then
          for (Iterator j = myResourcesSet.iterator(); j.hasNext(); ) {
              tmpOn = (ObjectName) j.next();
              try {
                  mbeanServer.setAttribute(tmpOn, new Attribute("StateProvider", tmpBool));
              }
              catch (Exception e) {
                  CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                         "Caught exception : " + e +
                                         "\n while invoking setStateProvider method on CIB resource named :\n" +
                                         tmpOn +
                                         " from CIB Application named :\n " + objectName +
                                         CIBMbeanNewLine +
                                         CIBMbeanLogMessageClosingString);
                  throw new CIBException("Exception in CIBApplication while invoking setStateProvider on a linked resource" , e);
              }
          }

          // enable/disable monitoring on all external resources last
          for (Iterator j = myExternalResourcesSet.iterator(); j.hasNext(); ) {
              tmpOn = (ObjectName) j.next();
              try {
                  mbeanServer.setAttribute(tmpOn, new Attribute("StateProvider", tmpBool));
              }
              catch (Exception e) {
                  CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                         "Caught exception : " + e +
                                         "\n while invoking setStateProvider method on CIB external resource named :\n" +
                                         tmpOn +
                                         " from CIB Application named :\n " + objectName +
                                         CIBMbeanNewLine +
                                         CIBMbeanLogMessageClosingString);
                  throw new CIBException("Exception in CIBApplication while invoking setStateProvider on a linked external resource" , e);
              }
          }
      }

      // know we can enable/disable monitoring in the application itself
      super.setStateProvider(val);
  }

  /**
   * Set the statisticProvider to val
   * @param val boolean
   * @throws CIBException
   */
  public void setStatisticProvider(boolean val) throws CIBException {

      if (!isRegistered) {
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                 "Impossible to enable/disable monitoring on connected servcies and resources !\n" +
                                 " CIBApplication " + objectName + "is unregistered, undefined mbeanserver " +
                                 CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
          throw new CIBException("Unregistered CIBApplication, cannot call setStatisticProvider on linked monitored objects");
      }
      else {

          // first propagate the enabling/disabling to connected resources and services
          ObjectName tmpOn;
          Boolean tmpBool = new Boolean(val);

          // enable/disable monitoring on all services first
          for (Iterator j = myServicesSet.iterator(); j.hasNext(); ) {
              tmpOn = (ObjectName) j.next();
              try {
                  mbeanServer.setAttribute(tmpOn, new Attribute("StatisticProvider", tmpBool));
              }
              catch (Exception e) {
                  CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                         "Caught exception : " + e +
                                         "\n while invoking setStatisticProvider method on CIB service named :\n" +
                                         tmpOn +
                                         " from CIB Application named :\n " + objectName +
                                         CIBMbeanNewLine +
                                         CIBMbeanLogMessageClosingString);
                  throw new CIBException("Exception in CIBApplication while invoking setStatisticProvider on a linked service" , e);
              }
          }

          // enable/disable monitoring on all resources then
          for (Iterator j = myResourcesSet.iterator(); j.hasNext(); ) {
              tmpOn = (ObjectName) j.next();
              try {
                  mbeanServer.setAttribute(tmpOn, new Attribute("StatisticProvider", tmpBool));
              }
              catch (Exception e) {
                  CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                         "Caught exception : " + e +
                                         "\n while invoking setStatisticProvider method on CIB resource named :\n" +
                                         tmpOn +
                                         " from CIB Application named :\n " + objectName +
                                         CIBMbeanNewLine +
                                         CIBMbeanLogMessageClosingString);
                  throw new CIBException("Exception in CIBApplication while invoking setStatisticProvider on a linked resource" , e);
              }
          }

          // enable/disable monitoring on all external resources last
          for (Iterator j = myExternalResourcesSet.iterator(); j.hasNext(); ) {
              tmpOn = (ObjectName) j.next();
              try {
                  mbeanServer.setAttribute(tmpOn, new Attribute("StatisticProvider", tmpBool));
              }
              catch (Exception e) {
                  CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                         "Caught exception : " + e +
                                         "\n while invoking setStatisticProvider method on CIB external resource named :\n" +
                                         tmpOn +
                                         " from CIB Application named :\n " + objectName +
                                         CIBMbeanNewLine +
                                         CIBMbeanLogMessageClosingString);
                  throw new CIBException("Exception in CIBApplication while invoking setStatisticProvider on a linked external resource" , e);
              }
          }
      }

      // know we can enable/disable monitoring in the application itself
      super.setStatisticProvider(val);
  }


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

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

  /**
   * Set the Role of the application
   * @param theRole String
   */
  public void setRole(String theRole) {
    myRole = theRole;
  }

  /**
   * Set the URL Description of the Application
   * @param theUrlDescription String
   */
  public void setUrlDescription(String theUrlDescription) {
    myUrlDescription = theUrlDescription;
  }

  /**
   * Allows to add a CIBApplication objectName in the list of ContainedApplications
   * @param objectName ObjectName
   */
  public void addCIBApplication(ObjectName objectName) {
    myApplicationsSet.add(objectName);
  }

  /**
   * Allows to remove a CIBApplication object name from the list of ContainedApplications
   * @param objectName ObjectName
   * @throws CIBException
   */
  public void removeCIBApplication(ObjectName objectName) throws CIBException {
    if (myApplicationsSet.contains(objectName)) {
      myApplicationsSet.remove(objectName);
    }
    else {
      String message = " Application " + this.objectName +
          " does not has Application " + objectName;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             "\n Application object is :\n" + this +
                             CIBMbeanNewLine + CIBMbeanLogMessageClosingString);
      throw new CIBException(message);
    }
  }

  /**
   * Allows to add a CIBService objectName in the list
   * of service managed object linked to the application
   * @param objectName ObjectName
   */
  public void addCIBService(ObjectName objectName) {
    myServicesSet.add(objectName);
  }

  /**
   * Allows to remove a service object name from the list associated
   * to the application
   * @param objectName ObjectName
   */
  public void removeCIBService(ObjectName objectName) throws CIBException {
    if (myServicesSet.contains(objectName)) {
      myServicesSet.remove(objectName);
    }
    else {
      String message = " Application " + this.objectName +
          " does not has Service " + objectName;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             "\n Application object is :\n" + this +
                             CIBMbeanNewLine + CIBMbeanLogMessageClosingString);
      throw new CIBException(message);
    }
  }

  /**
   * Allows to add an CIBExternalResource to the list of Object Names
   * Associated to the CIBApplication
   * @param objectName ObjectName
   */
  public void addCIBExternalResource(ObjectName objectName) {
    myExternalResourcesSet.add(objectName);
  }

  /**
   * Allows to remove an an CIBExternalResource from the list of Object Names
   * Associated to the CIBApplication
   * @param objectName ObjectName
   */
  public void removeCIBExternalResource(ObjectName objectName) throws
      CIBException {
    if (myExternalResourcesSet.contains(objectName)) {
      myExternalResourcesSet.remove(objectName);
    }
    else {
      String message = " Application " + this.objectName +
          " does not has External Resource " + objectName;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             "\n Application object is :\n" + this +
                             CIBMbeanNewLine + CIBMbeanLogMessageClosingString);
      throw new CIBException(message);
    }
  }

  /**
   *  Allows to set the Container object Name
   * @param objectName ObjectName
   */
  public void setApplicationContainer(ObjectName objectName) {
    myContainer = objectName;
  }

  // Interface MBean

  /**
   * Provides the application URL Description
   * @return String
   */
  public String getApplicationURLDescription() {
    if (myUrlDescription != null) {
      return myUrlDescription;
    }
    try {
      // systematic retrieval of perf stats to ensure uptodate data
      CIBApplicationConfiguration configProvider =
          (CIBApplicationConfiguration) myProviderHandler.getConfiguration(this,
          CIBProviderHandler.APPLICATION_CONFIG_TYPE);
      configProvider.init();
      return configProvider.getUrlDescription();
    }
    catch (CIBException ex) {
      String message = " Caught unexpected exception " + ex;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      return null;
    }

  }

  /**
   * Provides the role of an application instance in the JES environment.
   * @return String
   */
  public String getRole() {
    if (myRole != null) {
      return myRole;
    }
    try {
      // systematic retrieval of perf stats to ensure uptodate data
      CIBApplicationConfiguration configProvider =
          (CIBApplicationConfiguration) myProviderHandler.getConfiguration(this,
          CIBProviderHandler.APPLICATION_CONFIG_TYPE);
      configProvider.init();
      return configProvider.getRole();
    }
    catch (CIBException ex) {
      String message = " Caught unexpected exception " + ex;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      return null;
    }
  }

  /**
   * Return the list of CIBService object names
   * @return ObjectName[]
   */
  public ObjectName[] getServices() {
    return setToObjectNameArray(myServicesSet);
  }

  /**
   * Returns the object name of the Service identified by its Uri
   * @param uri String
   * @return ObjectName
   */
  public ObjectName getServiceByUri(String uri) throws CIBException {
    String message = "Could not find Service with URI : " + uri + "\n";
    if (!isRegistered) {
      throw new CIBException(message);
    }
    else {
      ObjectName elem;
      for (Iterator j = myServicesSet.iterator(); j.hasNext(); ) {
        elem = (ObjectName) j.next();
        try {
          String tmpUri = (String) mbeanServer.getAttribute(elem, "uri");
          if (tmpUri.equals(uri)) {
            return elem;
          }
        }
        catch (Exception e) {
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                 "Caught exception : " + e +
                                 "\n while retrieving service with uri " + uri +
                                 " in the mbean server.\n Application objet is : \n" +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
        }
      }
      throw new CIBException(message);
    }
  }

  /**
   * Returns the Object Name of the service identified by its name
   * @param name String
   * @return ObjectName
   */
  public ObjectName getServiceByName(String name) throws CIBException {
    String message = "Could not find Service with Name : " + name + "\n";
    if (!isRegistered) {
      throw new CIBException(message);
    }
    else {
      ObjectName elem;
      for (Iterator j = myServicesSet.iterator(); j.hasNext(); ) {
        elem = (ObjectName) j.next();
        try {
          String tmpName = (String) mbeanServer.getAttribute(elem, "name");
          if (tmpName.equals(name)) {
            return elem;
          }
        }
        catch (Exception e) {
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                 "Caught exception : " + e +
                                 "\n while retrieving service with name " +
                                 name +
                                 " in the mbean server.\n Application objet is : \n" +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
        }
      }
      throw new CIBException(message);
    }
  }

  /**
   * Returns the list of object names of all the resource associated
   * to the application
   * @return ObjectName[]
   */
  public ObjectName[] getResources() {
    return setToObjectNameArray(myResourcesSet);
  }

  /**
   * Returns the Object Name of a resource identified by its uri
   * @param name String
   * @return ObjectName
   */
  public ObjectName getResourceByName(String name) throws CIBException {
    String message = "Could not find Resource with Name : " + name + "\n";
    if (!isRegistered) {
      throw new CIBException(message);
    }
    else {
      ObjectName elem;
      for (Iterator j = myResourcesSet.iterator(); j.hasNext(); ) {
        elem = (ObjectName) j.next();
        try {
          String tmpName = (String) mbeanServer.getAttribute(elem, "name");
          if (tmpName.equals(name)) {
            return elem;
          }
        }
        catch (Exception e) {
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                 "Caught exception : " + e +
                                 "\n while retrieving Resource with name " +
                                 name +
                                 " in the mbean server.\n Application objet is : \n" +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
        }
      }
      throw new CIBException(message);
    }
  }

  /**
   * Return the list of External service object names associated to the application
   * @return ObjectName[]
   */
  public ObjectName[] getExternalResources() {
    return setToObjectNameArray(myExternalResourcesSet);
  }

  /**
   * Returns the object name of a ExternalResource associated to the application
   * identifies by its Uri
   * @param uri String
   * @return ObjectName
   */
  public ObjectName getExternalResourceByUri(String uri) throws CIBException {
    String message = "Could not find External Resource with URI : " + uri +
        "\n";
    if (!isRegistered) {
      throw new CIBException(message);
    }
    else {
      ObjectName elem;
      for (Iterator j = myExternalResourcesSet.iterator(); j.hasNext(); ) {
        elem = (ObjectName) j.next();
        try {
          String tmpUri = (String) mbeanServer.getAttribute(elem, "uri");
          if (tmpUri.equals(uri)) {
            return elem;
          }
        }
        catch (Exception e) {
          CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString +
                                 "Caught exception : " + e +
                                 "\n while retrieving External Resource with uri " +
                                 uri +
                                 " in the mbean server.\n Application objet is : \n" +
                                 this +CIBMbeanNewLine +
                                 CIBMbeanLogMessageClosingString);
        }
      }
      throw new CIBException(message);
    }
  }

  /**
   * Returns the object name of the application container
   * @return ObjectName
   */
  public ObjectName getContainer() {
    return myContainer;
  }

  /**
   * Returns the list of aggregated applications
   * @return ObjectName[]
   */
  public ObjectName[] getApplicationsSet() {
    return setToObjectNameArray(myApplicationsSet);
  }

  /**
   * setCIBProduct
   *
   * @param objectName ObjectName
   */
  public void setCIBProduct(ObjectName objectName) {
    myProduct = objectName;
  }

  /**
   * Returns the CIBProduct object name
   * @throws InvalidAttributeValueException
   * @return ObjectName
   */
  public ObjectName getProduct() throws InvalidAttributeValueException {
    if (myProduct != null) {
      return myProduct;
    }
    else {
      String message = " Unset Product for application ";
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      throw new InvalidAttributeValueException(message);
    }

  }

  /**
   * getDirectoryDN
   *
   * @return String
   */
  public String getDirectoryDN() {
    if (myDirectoryDN != null) return myDirectoryDN;

    try {
      // systematic retrieval of perf stats to ensure uptodate data
      CIBApplicationConfiguration configProvider =
          (CIBApplicationConfiguration) myProviderHandler.getConfiguration(this,
          CIBProviderHandler.APPLICATION_CONFIG_TYPE);
      configProvider.init();
      return configProvider.getDirectoryDN();
    }
    catch (CIBException ex) {
      String message = " Caught unexpected OpenType exception " + ex;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             this +CIBMbeanNewLine +
                             CIBMbeanLogMessageClosingString);
      return null;
    }
  }

  /**
   * addCIBResource
   *
   * @param objectName ObjectName
   */
  public void addCIBResource(ObjectName objectName) {
    myResourcesSet.add(objectName);
  }

  /**
   * removeCIBResource
   *
   * @param objectName ObjectName
   */
  public void removeCIBResource(ObjectName objectName) throws CIBException {
    if (myResourcesSet.contains(objectName)) {
      myResourcesSet.remove(objectName);
    }
    else {
      String message = " Application " + this.objectName +
          " does not use Ressource " + objectName;
      CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                             "\n Application object is :\n" + this +
                             CIBMbeanNewLine + CIBMbeanLogMessageClosingString);
      throw new CIBException(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
        CIBApplicationPerfStats applicationPerfStatsProvider =
            (CIBApplicationPerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.APPLICATION_PERFSTATS_TYPE);
        applicationPerfStatsProvider.init();
        return applicationPerfStatsProvider;
      }
    }
    catch (CIBException ex) {
      String message = " Unexpected exception " + ex +
          " while calling getStats on Application : " + 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;
    }
    try {
      // systematic retrieval of perf stats to ensure uptodate data
      CIBStatistic cibStatistic;
      CIBApplicationPerfStats applicationPerfStatsProvider =
          (CIBApplicationPerfStats) myProviderHandler.getPerfStats(this,
          CIBProviderHandler.APPLICATION_PERFSTATS_TYPE);
      applicationPerfStatsProvider.init();
      if ( (cibStatistic = (CIBStatistic) applicationPerfStatsProvider.
            getStatistic(name)) != null) {
        return cibStatistic.toCompositeData();
      }
      else {
        String message = " Unexisting statistic " + name + " in Application : " +
            this.objectName;
        CIBMbeanLogger.warning(CIBMbeanLogMessageHeaderString + message +
                               this +CIBMbeanNewLine +
                               CIBMbeanLogMessageClosingString);
        throw new CIBAttributeNotFoundException(message,
                                                " CIBApplicationPerfStats ",
                                                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 Application : \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;
        CIBApplicationPerfStats applicationPerfStatsProvider =
            (CIBApplicationPerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.APPLICATION_PERFSTATS_TYPE);
        applicationPerfStatsProvider.init();

        if (((statisticArray = applicationPerfStatsProvider.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) applicationPerfStatsProvider.
                  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 Application : \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
        CIBApplicationPerfStats applicationPerfStatsProvider =
            (CIBApplicationPerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.APPLICATION_PERFSTATS_TYPE);
        applicationPerfStatsProvider.init();
        return applicationPerfStatsProvider.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
        CIBApplicationPerfStats applicationPerfStatsProvider =
            (CIBApplicationPerfStats) myProviderHandler.getPerfStats(this,
            CIBProviderHandler.APPLICATION_PERFSTATS_TYPE);
        applicationPerfStatsProvider.init();
        return applicationPerfStatsProvider.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.APPLICATION_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.APPLICATION_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.APPLICATION_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.APPLICATION_STATE_TYPE);
      availStatusProvider.init();
      result = availStatusProvider.getState();
      if ((result != availStatus) &&
          (isEventProvider())) {
        eventBroadcaster.sendNotification(
          new AttributeChangeNotification(this, eventNumber++, System.currentTimeMillis(), null,
                                          "AvailibilityStatusState", "int",
                                          new Integer(opStatus), new Integer(result)));
      }
      availStatus = result;
      return availStatus;
    }
    catch (CIBIOException ex) {
      String message =
          " caught IO exception in CIB SDK while calling getAvailibilityStatusState ";
      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.APPLICATION_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.APPLICATION_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);
    }
  }

// Private methods
  private ObjectName[] setToObjectNameArray(Set theSet) {
    ObjectName[] result = null;
    ObjectName elem = null;
    result = new ObjectName[theSet.size()];
    int i = 0;
    for (Iterator j = theSet.iterator(); j.hasNext(); ) {
      elem = (ObjectName) j.next();
      result[i] = elem;
      i++;
    }
    return result;
  }
}
