Save This Page
Home » openjdk-7 » javax » management » relation » [javadoc | source]
    1   /*
    2    * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.management.relation;
   27   
   28   import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER;
   29   import static com.sun.jmx.mbeanserver.Util.cast;
   30   
   31   import java.util.ArrayList;
   32   import java.util.Date;
   33   import java.util.HashMap;
   34   import java.util.Iterator;
   35   import java.util.List;
   36   import java.util.Map;
   37   import java.util.Set;
   38   import java.util.concurrent.atomic.AtomicLong;
   39   import java.util.logging.Level;
   40   
   41   import javax.management.Attribute;
   42   import javax.management.AttributeNotFoundException;
   43   import javax.management.InstanceNotFoundException;
   44   import javax.management.InvalidAttributeValueException;
   45   import javax.management.MBeanException;
   46   import javax.management.MBeanNotificationInfo;
   47   import javax.management.MBeanRegistration;
   48   import javax.management.MBeanServer;
   49   import javax.management.MBeanServerDelegate;
   50   import javax.management.MBeanServerNotification;
   51   import javax.management.Notification;
   52   import javax.management.NotificationBroadcasterSupport;
   53   import javax.management.NotificationListener;
   54   import javax.management.ObjectName;
   55   import javax.management.ReflectionException;
   56   
   57   /**
   58    * The Relation Service is in charge of creating and deleting relation types
   59    * and relations, of handling the consistency and of providing query
   60    * mechanisms.
   61    * <P>It implements the NotificationBroadcaster by extending
   62    * NotificationBroadcasterSupport to send notifications when a relation is
   63    * removed from it.
   64    * <P>It implements the NotificationListener interface to be able to receive
   65    * notifications concerning unregistration of MBeans referenced in relation
   66    * roles and of relation MBeans.
   67    * <P>It implements the MBeanRegistration interface to be able to retrieve
   68    * its ObjectName and MBean Server.
   69    *
   70    * @since 1.5
   71    */
   72   public class RelationService extends NotificationBroadcasterSupport
   73       implements RelationServiceMBean, MBeanRegistration, NotificationListener {
   74   
   75       //
   76       // Private members
   77       //
   78   
   79       // Map associating:
   80       //      <relation id> -> <RelationSupport object/ObjectName>
   81       // depending if the relation has been created using createRelation()
   82       // method (so internally handled) or is an MBean added as a relation by the
   83       // user
   84       private Map<String,Object> myRelId2ObjMap = new HashMap<String,Object>();
   85   
   86       // Map associating:
   87       //      <relation id> -> <relation type name>
   88       private Map<String,String> myRelId2RelTypeMap = new HashMap<String,String>();
   89   
   90       // Map associating:
   91       //      <relation MBean Object Name> -> <relation id>
   92       private Map<ObjectName,String> myRelMBeanObjName2RelIdMap =
   93           new HashMap<ObjectName,String>();
   94   
   95       // Map associating:
   96       //       <relation type name> -> <RelationType object>
   97       private Map<String,RelationType> myRelType2ObjMap =
   98           new HashMap<String,RelationType>();
   99   
  100       // Map associating:
  101       //       <relation type name> -> ArrayList of <relation id>
  102       // to list all the relations of a given type
  103       private Map<String,List<String>> myRelType2RelIdsMap =
  104           new HashMap<String,List<String>>();
  105   
  106       // Map associating:
  107       //       <ObjectName> -> HashMap
  108       // the value HashMap mapping:
  109       //       <relation id> -> ArrayList of <role name>
  110       // to track where a given MBean is referenced.
  111       private Map<ObjectName,Map<String,List<String>>>
  112           myRefedMBeanObjName2RelIdsMap =
  113               new HashMap<ObjectName,Map<String,List<String>>>();
  114   
  115       // Flag to indicate if, when a notification is received for the
  116       // unregistration of an MBean referenced in a relation, if an immediate
  117       // "purge" of the relations (look for the relations no
  118       // longer valid) has to be performed , or if that will be performed only
  119       // when the purgeRelations method will be explicitly called.
  120       // true is immediate purge.
  121       private boolean myPurgeFlag = true;
  122   
  123       // Internal counter to provide sequence numbers for notifications sent by:
  124       // - the Relation Service
  125       // - a relation handled by the Relation Service
  126       private final AtomicLong atomicSeqNo = new AtomicLong();
  127   
  128       // ObjectName used to register the Relation Service in the MBean Server
  129       private ObjectName myObjName = null;
  130   
  131       // MBean Server where the Relation Service is registered
  132       private MBeanServer myMBeanServer = null;
  133   
  134       // Filter registered in the MBean Server with the Relation Service to be
  135       // informed of referenced MBean unregistrations
  136       private MBeanServerNotificationFilter myUnregNtfFilter = null;
  137   
  138       // List of unregistration notifications received (storage used if purge
  139       // of relations when unregistering a referenced MBean is not immediate but
  140       // on user request)
  141       private List<MBeanServerNotification> myUnregNtfList =
  142           new ArrayList<MBeanServerNotification>();
  143   
  144       //
  145       // Constructor
  146       //
  147   
  148       /**
  149        * Constructor.
  150        *
  151        * @param immediatePurgeFlag  flag to indicate when a notification is
  152        * received for the unregistration of an MBean referenced in a relation, if
  153        * an immediate "purge" of the relations (look for the relations no
  154        * longer valid) has to be performed , or if that will be performed only
  155        * when the purgeRelations method will be explicitly called.
  156        * <P>true is immediate purge.
  157        */
  158       public RelationService(boolean immediatePurgeFlag) {
  159   
  160           RELATION_LOGGER.entering(RelationService.class.getName(),
  161                   "RelationService");
  162   
  163           setPurgeFlag(immediatePurgeFlag);
  164   
  165           RELATION_LOGGER.exiting(RelationService.class.getName(),
  166                   "RelationService");
  167           return;
  168       }
  169   
  170       /**
  171        * Checks if the Relation Service is active.
  172        * Current condition is that the Relation Service must be registered in the
  173        * MBean Server
  174        *
  175        * @exception RelationServiceNotRegisteredException  if it is not
  176        * registered
  177        */
  178       public void isActive()
  179           throws RelationServiceNotRegisteredException {
  180           if (myMBeanServer == null) {
  181               // MBean Server not set by preRegister(): relation service not
  182               // registered
  183               String excMsg =
  184                   "Relation Service not registered in the MBean Server.";
  185               throw new RelationServiceNotRegisteredException(excMsg);
  186           }
  187           return;
  188       }
  189   
  190       //
  191       // MBeanRegistration interface
  192       //
  193   
  194       // Pre-registration: retrieves its ObjectName and MBean Server
  195       //
  196       // No exception thrown.
  197       public ObjectName preRegister(MBeanServer server,
  198                                     ObjectName name)
  199           throws Exception {
  200   
  201           myMBeanServer = server;
  202           myObjName = name;
  203           return name;
  204       }
  205   
  206       // Post-registration: does nothing
  207       public void postRegister(Boolean registrationDone) {
  208           return;
  209       }
  210   
  211       // Pre-unregistration: does nothing
  212       public void preDeregister()
  213           throws Exception {
  214           return;
  215       }
  216   
  217       // Post-unregistration: does nothing
  218       public void postDeregister() {
  219           return;
  220       }
  221   
  222       //
  223       // Accessors
  224       //
  225   
  226       /**
  227        * Returns the flag to indicate if when a notification is received for the
  228        * unregistration of an MBean referenced in a relation, if an immediate
  229        * "purge" of the relations (look for the relations no longer valid)
  230        * has to be performed , or if that will be performed only when the
  231        * purgeRelations method will be explicitly called.
  232        * <P>true is immediate purge.
  233        *
  234        * @return true if purges are automatic.
  235        *
  236        * @see #setPurgeFlag
  237        */
  238       public boolean getPurgeFlag() {
  239           return myPurgeFlag;
  240       }
  241   
  242       /**
  243        * Sets the flag to indicate if when a notification is received for the
  244        * unregistration of an MBean referenced in a relation, if an immediate
  245        * "purge" of the relations (look for the relations no longer valid)
  246        * has to be performed , or if that will be performed only when the
  247        * purgeRelations method will be explicitly called.
  248        * <P>true is immediate purge.
  249        *
  250        * @param purgeFlag  flag
  251        *
  252        * @see #getPurgeFlag
  253        */
  254       public void setPurgeFlag(boolean purgeFlag) {
  255   
  256           myPurgeFlag = purgeFlag;
  257           return;
  258       }
  259   
  260       //
  261       // Relation type handling
  262       //
  263   
  264       /**
  265        * Creates a relation type (a RelationTypeSupport object) with given
  266        * role infos (provided by the RoleInfo objects), and adds it in the
  267        * Relation Service.
  268        *
  269        * @param relationTypeName  name of the relation type
  270        * @param roleInfoArray  array of role infos
  271        *
  272        * @exception IllegalArgumentException  if null parameter
  273        * @exception InvalidRelationTypeException  If:
  274        * <P>- there is already a relation type with that name
  275        * <P>- the same name has been used for two different role infos
  276        * <P>- no role info provided
  277        * <P>- one null role info provided
  278        */
  279       public void createRelationType(String relationTypeName,
  280                                      RoleInfo[] roleInfoArray)
  281           throws IllegalArgumentException,
  282                  InvalidRelationTypeException {
  283   
  284           if (relationTypeName == null || roleInfoArray == null) {
  285               String excMsg = "Invalid parameter.";
  286               throw new IllegalArgumentException(excMsg);
  287           }
  288   
  289           RELATION_LOGGER.entering(RelationService.class.getName(),
  290                   "createRelationType", relationTypeName);
  291   
  292           // Can throw an InvalidRelationTypeException
  293           RelationType relType =
  294               new RelationTypeSupport(relationTypeName, roleInfoArray);
  295   
  296           addRelationTypeInt(relType);
  297   
  298           RELATION_LOGGER.exiting(RelationService.class.getName(),
  299                   "createRelationType");
  300           return;
  301       }
  302   
  303       /**
  304        * Adds given object as a relation type. The object is expected to
  305        * implement the RelationType interface.
  306        *
  307        * @param relationTypeObj  relation type object (implementing the
  308        * RelationType interface)
  309        *
  310        * @exception IllegalArgumentException  if null parameter or if
  311        * {@link RelationType#getRelationTypeName
  312        * relationTypeObj.getRelationTypeName()} returns null.
  313        * @exception InvalidRelationTypeException  if:
  314        * <P>- the same name has been used for two different roles
  315        * <P>- no role info provided
  316        * <P>- one null role info provided
  317        * <P>- there is already a relation type with that name
  318        */
  319       public void addRelationType(RelationType relationTypeObj)
  320           throws IllegalArgumentException,
  321                  InvalidRelationTypeException {
  322   
  323           if (relationTypeObj == null) {
  324               String excMsg = "Invalid parameter.";
  325               throw new IllegalArgumentException(excMsg);
  326           }
  327   
  328           RELATION_LOGGER.entering(RelationService.class.getName(),
  329                   "addRelationType");
  330   
  331           // Checks the role infos
  332           List<RoleInfo> roleInfoList = relationTypeObj.getRoleInfos();
  333           if (roleInfoList == null) {
  334               String excMsg = "No role info provided.";
  335               throw new InvalidRelationTypeException(excMsg);
  336           }
  337   
  338           RoleInfo[] roleInfoArray = new RoleInfo[roleInfoList.size()];
  339           int i = 0;
  340           for (RoleInfo currRoleInfo : roleInfoList) {
  341               roleInfoArray[i] = currRoleInfo;
  342               i++;
  343           }
  344           // Can throw InvalidRelationTypeException
  345           RelationTypeSupport.checkRoleInfos(roleInfoArray);
  346   
  347           addRelationTypeInt(relationTypeObj);
  348   
  349           RELATION_LOGGER.exiting(RelationService.class.getName(),
  350                   "addRelationType");
  351           return;
  352        }
  353   
  354       /**
  355        * Retrieves names of all known relation types.
  356        *
  357        * @return ArrayList of relation type names (Strings)
  358        */
  359       public List<String> getAllRelationTypeNames() {
  360           ArrayList<String> result;
  361           synchronized(myRelType2ObjMap) {
  362               result = new ArrayList<String>(myRelType2ObjMap.keySet());
  363           }
  364           return result;
  365       }
  366   
  367       /**
  368        * Retrieves list of role infos (RoleInfo objects) of a given relation
  369        * type.
  370        *
  371        * @param relationTypeName  name of relation type
  372        *
  373        * @return ArrayList of RoleInfo.
  374        *
  375        * @exception IllegalArgumentException  if null parameter
  376        * @exception RelationTypeNotFoundException  if there is no relation type
  377        * with that name.
  378        */
  379       public List<RoleInfo> getRoleInfos(String relationTypeName)
  380           throws IllegalArgumentException,
  381                  RelationTypeNotFoundException {
  382   
  383           if (relationTypeName == null) {
  384               String excMsg = "Invalid parameter.";
  385               throw new IllegalArgumentException(excMsg);
  386           }
  387   
  388           RELATION_LOGGER.entering(RelationService.class.getName(),
  389                   "getRoleInfos", relationTypeName);
  390   
  391           // Can throw a RelationTypeNotFoundException
  392           RelationType relType = getRelationType(relationTypeName);
  393   
  394           RELATION_LOGGER.exiting(RelationService.class.getName(),
  395                   "getRoleInfos");
  396           return relType.getRoleInfos();
  397       }
  398   
  399       /**
  400        * Retrieves role info for given role name of a given relation type.
  401        *
  402        * @param relationTypeName  name of relation type
  403        * @param roleInfoName  name of role
  404        *
  405        * @return RoleInfo object.
  406        *
  407        * @exception IllegalArgumentException  if null parameter
  408        * @exception RelationTypeNotFoundException  if the relation type is not
  409        * known in the Relation Service
  410        * @exception RoleInfoNotFoundException  if the role is not part of the
  411        * relation type.
  412        */
  413       public RoleInfo getRoleInfo(String relationTypeName,
  414                                   String roleInfoName)
  415           throws IllegalArgumentException,
  416                  RelationTypeNotFoundException,
  417                  RoleInfoNotFoundException {
  418   
  419           if (relationTypeName == null || roleInfoName == null) {
  420               String excMsg = "Invalid parameter.";
  421               throw new IllegalArgumentException(excMsg);
  422           }
  423   
  424           RELATION_LOGGER.entering(RelationService.class.getName(),
  425                   "getRoleInfo", new Object[] {relationTypeName, roleInfoName});
  426   
  427           // Can throw a RelationTypeNotFoundException
  428           RelationType relType = getRelationType(relationTypeName);
  429   
  430           // Can throw a RoleInfoNotFoundException
  431           RoleInfo roleInfo = relType.getRoleInfo(roleInfoName);
  432   
  433           RELATION_LOGGER.exiting(RelationService.class.getName(),
  434                   "getRoleInfo");
  435           return roleInfo;
  436       }
  437   
  438       /**
  439        * Removes given relation type from Relation Service.
  440        * <P>The relation objects of that type will be removed from the
  441        * Relation Service.
  442        *
  443        * @param relationTypeName  name of the relation type to be removed
  444        *
  445        * @exception RelationServiceNotRegisteredException  if the Relation
  446        * Service is not registered in the MBean Server
  447        * @exception IllegalArgumentException  if null parameter
  448        * @exception RelationTypeNotFoundException  If there is no relation type
  449        * with that name
  450        */
  451       public void removeRelationType(String relationTypeName)
  452           throws RelationServiceNotRegisteredException,
  453                  IllegalArgumentException,
  454                  RelationTypeNotFoundException {
  455   
  456           // Can throw RelationServiceNotRegisteredException
  457           isActive();
  458   
  459           if (relationTypeName == null) {
  460               String excMsg = "Invalid parameter.";
  461               throw new IllegalArgumentException(excMsg);
  462           }
  463   
  464           RELATION_LOGGER.entering(RelationService.class.getName(),
  465                   "removeRelationType", relationTypeName);
  466   
  467           // Checks if the relation type to be removed exists
  468           // Can throw a RelationTypeNotFoundException
  469           RelationType relType = getRelationType(relationTypeName);
  470   
  471           // Retrieves the relation ids for relations of that type
  472           List<String> relIdList = null;
  473           synchronized(myRelType2RelIdsMap) {
  474               // Note: take a copy of the list as it is a part of a map that
  475               //       will be updated by removeRelation() below.
  476               List<String> relIdList1 =
  477                   myRelType2RelIdsMap.get(relationTypeName);
  478               if (relIdList1 != null) {
  479                   relIdList = new ArrayList<String>(relIdList1);
  480               }
  481           }
  482   
  483           // Removes the relation type from all maps
  484           synchronized(myRelType2ObjMap) {
  485               myRelType2ObjMap.remove(relationTypeName);
  486           }
  487           synchronized(myRelType2RelIdsMap) {
  488               myRelType2RelIdsMap.remove(relationTypeName);
  489           }
  490   
  491           // Removes all relations of that type
  492           if (relIdList != null) {
  493               for (String currRelId : relIdList) {
  494                   // Note: will remove it from myRelId2RelTypeMap :)
  495                   //
  496                   // Can throw RelationServiceNotRegisteredException (detected
  497                   // above)
  498                   // Shall not throw a RelationNotFoundException
  499                   try {
  500                       removeRelation(currRelId);
  501                   } catch (RelationNotFoundException exc1) {
  502                       throw new RuntimeException(exc1.getMessage());
  503                   }
  504               }
  505           }
  506   
  507           RELATION_LOGGER.exiting(RelationService.class.getName(),
  508                   "removeRelationType");
  509           return;
  510       }
  511   
  512       //
  513       // Relation handling
  514       //
  515   
  516       /**
  517        * Creates a simple relation (represented by a RelationSupport object) of
  518        * given relation type, and adds it in the Relation Service.
  519        * <P>Roles are initialized according to the role list provided in
  520        * parameter. The ones not initialized in this way are set to an empty
  521        * ArrayList of ObjectNames.
  522        * <P>A RelationNotification, with type RELATION_BASIC_CREATION, is sent.
  523        *
  524        * @param relationId  relation identifier, to identify uniquely the relation
  525        * inside the Relation Service
  526        * @param relationTypeName  name of the relation type (has to be created
  527        * in the Relation Service)
  528        * @param roleList  role list to initialize roles of the relation (can
  529        * be null).
  530        *
  531        * @exception RelationServiceNotRegisteredException  if the Relation
  532        * Service is not registered in the MBean Server
  533        * @exception IllegalArgumentException  if null parameter, except the role
  534        * list which can be null if no role initialization
  535        * @exception RoleNotFoundException  if a value is provided for a role
  536        * that does not exist in the relation type
  537        * @exception InvalidRelationIdException  if relation id already used
  538        * @exception RelationTypeNotFoundException  if relation type not known in
  539        * Relation Service
  540        * @exception InvalidRoleValueException if:
  541        * <P>- the same role name is used for two different roles
  542        * <P>- the number of referenced MBeans in given value is less than
  543        * expected minimum degree
  544        * <P>- the number of referenced MBeans in provided value exceeds expected
  545        * maximum degree
  546        * <P>- one referenced MBean in the value is not an Object of the MBean
  547        * class expected for that role
  548        * <P>- an MBean provided for that role does not exist
  549        */
  550       public void createRelation(String relationId,
  551                                  String relationTypeName,
  552                                  RoleList roleList)
  553           throws RelationServiceNotRegisteredException,
  554                  IllegalArgumentException,
  555                  RoleNotFoundException,
  556                  InvalidRelationIdException,
  557                  RelationTypeNotFoundException,
  558                  InvalidRoleValueException {
  559   
  560           // Can throw RelationServiceNotRegisteredException
  561           isActive();
  562   
  563           if (relationId == null ||
  564               relationTypeName == null) {
  565               String excMsg = "Invalid parameter.";
  566               throw new IllegalArgumentException(excMsg);
  567           }
  568   
  569           RELATION_LOGGER.entering(RelationService.class.getName(),
  570                   "createRelation",
  571                   new Object[] {relationId, relationTypeName, roleList});
  572   
  573           // Creates RelationSupport object
  574           // Can throw InvalidRoleValueException
  575           RelationSupport relObj = new RelationSupport(relationId,
  576                                                  myObjName,
  577                                                  relationTypeName,
  578                                                  roleList);
  579   
  580           // Adds relation object as a relation into the Relation Service
  581           // Can throw RoleNotFoundException, InvalidRelationId,
  582           // RelationTypeNotFoundException, InvalidRoleValueException
  583           //
  584           // Cannot throw MBeanException
  585           addRelationInt(true,
  586                          relObj,
  587                          null,
  588                          relationId,
  589                          relationTypeName,
  590                          roleList);
  591           RELATION_LOGGER.exiting(RelationService.class.getName(),
  592                   "createRelation");
  593           return;
  594       }
  595   
  596       /**
  597        * Adds an MBean created by the user (and registered by him in the MBean
  598        * Server) as a relation in the Relation Service.
  599        * <P>To be added as a relation, the MBean must conform to the
  600        * following:
  601        * <P>- implement the Relation interface
  602        * <P>- have for RelationService ObjectName the ObjectName of current
  603        * Relation Service
  604        * <P>- have a relation id unique and unused in current Relation Service
  605        * <P>- have for relation type a relation type created in the Relation
  606        * Service
  607        * <P>- have roles conforming to the role info provided in the relation
  608        * type.
  609        *
  610        * @param relationObjectName  ObjectName of the relation MBean to be added.
  611        *
  612        * @exception IllegalArgumentException  if null parameter
  613        * @exception RelationServiceNotRegisteredException  if the Relation
  614        * Service is not registered in the MBean Server
  615        * @exception NoSuchMethodException  If the MBean does not implement the
  616        * Relation interface
  617        * @exception InvalidRelationIdException  if:
  618        * <P>- no relation identifier in MBean
  619        * <P>- the relation identifier is already used in the Relation Service
  620        * @exception InstanceNotFoundException  if the MBean for given ObjectName
  621        * has not been registered
  622        * @exception InvalidRelationServiceException  if:
  623        * <P>- no Relation Service name in MBean
  624        * <P>- the Relation Service name in the MBean is not the one of the
  625        * current Relation Service
  626        * @exception RelationTypeNotFoundException  if:
  627        * <P>- no relation type name in MBean
  628        * <P>- the relation type name in MBean does not correspond to a relation
  629        * type created in the Relation Service
  630        * @exception InvalidRoleValueException  if:
  631        * <P>- the number of referenced MBeans in a role is less than
  632        * expected minimum degree
  633        * <P>- the number of referenced MBeans in a role exceeds expected
  634        * maximum degree
  635        * <P>- one referenced MBean in the value is not an Object of the MBean
  636        * class expected for that role
  637        * <P>- an MBean provided for a role does not exist
  638        * @exception RoleNotFoundException  if a value is provided for a role
  639        * that does not exist in the relation type
  640        */
  641       public void addRelation(ObjectName relationObjectName)
  642           throws IllegalArgumentException,
  643                  RelationServiceNotRegisteredException,
  644                  NoSuchMethodException,
  645                  InvalidRelationIdException,
  646                  InstanceNotFoundException,
  647                  InvalidRelationServiceException,
  648                  RelationTypeNotFoundException,
  649                  RoleNotFoundException,
  650                  InvalidRoleValueException {
  651   
  652           if (relationObjectName == null) {
  653               String excMsg = "Invalid parameter.";
  654               throw new IllegalArgumentException(excMsg);
  655           }
  656   
  657           RELATION_LOGGER.entering(RelationService.class.getName(),
  658                   "addRelation", relationObjectName);
  659   
  660           // Can throw RelationServiceNotRegisteredException
  661           isActive();
  662   
  663           // Checks that the relation MBean implements the Relation interface.
  664           // It will also check that the provided ObjectName corresponds to a
  665           // registered MBean (else will throw an InstanceNotFoundException)
  666           if ((!(myMBeanServer.isInstanceOf(relationObjectName, "javax.management.relation.Relation")))) {
  667               String excMsg = "This MBean does not implement the Relation interface.";
  668               throw new NoSuchMethodException(excMsg);
  669           }
  670           // Checks there is a relation id in the relation MBean (its uniqueness
  671           // is checked in addRelationInt())
  672           // Can throw InstanceNotFoundException (but detected above)
  673           // No MBeanException as no exception raised by this method, and no
  674           // ReflectionException
  675           String relId;
  676           try {
  677               relId = (String)(myMBeanServer.getAttribute(relationObjectName,
  678                                                           "RelationId"));
  679   
  680           } catch (MBeanException exc1) {
  681               throw new RuntimeException(
  682                                        (exc1.getTargetException()).getMessage());
  683           } catch (ReflectionException exc2) {
  684               throw new RuntimeException(exc2.getMessage());
  685           } catch (AttributeNotFoundException exc3) {
  686               throw new RuntimeException(exc3.getMessage());
  687           }
  688   
  689           if (relId == null) {
  690               String excMsg = "This MBean does not provide a relation id.";
  691               throw new InvalidRelationIdException(excMsg);
  692           }
  693           // Checks that the Relation Service where the relation MBean is
  694           // expected to be added is the current one
  695           // Can throw InstanceNotFoundException (but detected above)
  696           // No MBeanException as no exception raised by this method, no
  697           // ReflectionException
  698           ObjectName relServObjName;
  699           try {
  700               relServObjName = (ObjectName)
  701                   (myMBeanServer.getAttribute(relationObjectName,
  702                                               "RelationServiceName"));
  703   
  704           } catch (MBeanException exc1) {
  705               throw new RuntimeException(
  706                                        (exc1.getTargetException()).getMessage());
  707           } catch (ReflectionException exc2) {
  708               throw new RuntimeException(exc2.getMessage());
  709           } catch (AttributeNotFoundException exc3) {
  710               throw new RuntimeException(exc3.getMessage());
  711           }
  712   
  713           boolean badRelServFlag = false;
  714           if (relServObjName == null) {
  715               badRelServFlag = true;
  716   
  717           } else if (!(relServObjName.equals(myObjName))) {
  718               badRelServFlag = true;
  719           }
  720           if (badRelServFlag) {
  721               String excMsg = "The Relation Service referenced in the MBean is not the current one.";
  722               throw new InvalidRelationServiceException(excMsg);
  723           }
  724           // Checks that a relation type has been specified for the relation
  725           // Can throw InstanceNotFoundException (but detected above)
  726           // No MBeanException as no exception raised by this method, no
  727           // ReflectionException
  728           String relTypeName;
  729           try {
  730               relTypeName = (String)(myMBeanServer.getAttribute(relationObjectName,
  731                                                                 "RelationTypeName"));
  732   
  733           } catch (MBeanException exc1) {
  734               throw new RuntimeException(
  735                                        (exc1.getTargetException()).getMessage());
  736           }catch (ReflectionException exc2) {
  737               throw new RuntimeException(exc2.getMessage());
  738           } catch (AttributeNotFoundException exc3) {
  739               throw new RuntimeException(exc3.getMessage());
  740           }
  741           if (relTypeName == null) {
  742               String excMsg = "No relation type provided.";
  743               throw new RelationTypeNotFoundException(excMsg);
  744           }
  745           // Retrieves all roles without considering read mode
  746           // Can throw InstanceNotFoundException (but detected above)
  747           // No MBeanException as no exception raised by this method, no
  748           // ReflectionException
  749           RoleList roleList;
  750           try {
  751               roleList = (RoleList)(myMBeanServer.invoke(relationObjectName,
  752                                                          "retrieveAllRoles",
  753                                                          null,
  754                                                          null));
  755           } catch (MBeanException exc1) {
  756               throw new RuntimeException(
  757                                        (exc1.getTargetException()).getMessage());
  758           } catch (ReflectionException exc2) {
  759               throw new RuntimeException(exc2.getMessage());
  760           }
  761   
  762           // Can throw RoleNotFoundException, InvalidRelationIdException,
  763           // RelationTypeNotFoundException, InvalidRoleValueException
  764           addRelationInt(false,
  765                          null,
  766                          relationObjectName,
  767                          relId,
  768                          relTypeName,
  769                          roleList);
  770           // Adds relation MBean ObjectName in map
  771           synchronized(myRelMBeanObjName2RelIdMap) {
  772               myRelMBeanObjName2RelIdMap.put(relationObjectName, relId);
  773           }
  774   
  775           // Updates flag to specify that the relation is managed by the Relation
  776           // Service
  777           // This flag and setter are inherited from RelationSupport and not parts
  778           // of the Relation interface, so may be not supported.
  779           try {
  780               myMBeanServer.setAttribute(relationObjectName,
  781                                          new Attribute(
  782                                            "RelationServiceManagementFlag",
  783                                            Boolean.TRUE));
  784           } catch (Exception exc) {
  785               // OK : The flag is not supported.
  786           }
  787   
  788           // Updates listener information to received notification for
  789           // unregistration of this MBean
  790           List<ObjectName> newRefList = new ArrayList<ObjectName>();
  791           newRefList.add(relationObjectName);
  792           updateUnregistrationListener(newRefList, null);
  793   
  794           RELATION_LOGGER.exiting(RelationService.class.getName(),
  795                   "addRelation");
  796           return;
  797       }
  798   
  799       /**
  800        * If the relation is represented by an MBean (created by the user and
  801        * added as a relation in the Relation Service), returns the ObjectName of
  802        * the MBean.
  803        *
  804        * @param relationId  relation id identifying the relation
  805        *
  806        * @return ObjectName of the corresponding relation MBean, or null if
  807        * the relation is not an MBean.
  808        *
  809        * @exception IllegalArgumentException  if null parameter
  810        * @exception RelationNotFoundException there is no relation associated
  811        * to that id
  812        */
  813       public ObjectName isRelationMBean(String relationId)
  814           throws IllegalArgumentException,
  815                  RelationNotFoundException{
  816   
  817           if (relationId == null) {
  818               String excMsg = "Invalid parameter.";
  819               throw new IllegalArgumentException(excMsg);
  820           }
  821   
  822           RELATION_LOGGER.entering(RelationService.class.getName(),
  823                   "isRelationMBean", relationId);
  824   
  825           // Can throw RelationNotFoundException
  826           Object result = getRelation(relationId);
  827           if (result instanceof ObjectName) {
  828               return ((ObjectName)result);
  829           } else {
  830               return null;
  831           }
  832       }
  833   
  834       /**
  835        * Returns the relation id associated to the given ObjectName if the
  836        * MBean has been added as a relation in the Relation Service.
  837        *
  838        * @param objectName  ObjectName of supposed relation
  839        *
  840        * @return relation id (String) or null (if the ObjectName is not a
  841        * relation handled by the Relation Service)
  842        *
  843        * @exception IllegalArgumentException  if null parameter
  844        */
  845       public String isRelation(ObjectName objectName)
  846           throws IllegalArgumentException {
  847   
  848           if (objectName == null) {
  849               String excMsg = "Invalid parameter.";
  850               throw new IllegalArgumentException(excMsg);
  851           }
  852   
  853           RELATION_LOGGER.entering(RelationService.class.getName(),
  854                   "isRelation", objectName);
  855   
  856           String result = null;
  857           synchronized(myRelMBeanObjName2RelIdMap) {
  858               String relId = myRelMBeanObjName2RelIdMap.get(objectName);
  859               if (relId != null) {
  860                   result = relId;
  861               }
  862           }
  863           return result;
  864       }
  865   
  866       /**
  867        * Checks if there is a relation identified in Relation Service with given
  868        * relation id.
  869        *
  870        * @param relationId  relation id identifying the relation
  871        *
  872        * @return boolean: true if there is a relation, false else
  873        *
  874        * @exception IllegalArgumentException  if null parameter
  875        */
  876       public Boolean hasRelation(String relationId)
  877           throws IllegalArgumentException {
  878   
  879           if (relationId == null) {
  880               String excMsg = "Invalid parameter.";
  881               throw new IllegalArgumentException(excMsg);
  882           }
  883   
  884           RELATION_LOGGER.entering(RelationService.class.getName(),
  885                   "hasRelation", relationId);
  886   
  887           try {
  888               // Can throw RelationNotFoundException
  889               Object result = getRelation(relationId);
  890               return true;
  891           } catch (RelationNotFoundException exc) {
  892               return false;
  893           }
  894       }
  895   
  896       /**
  897        * Returns all the relation ids for all the relations handled by the
  898        * Relation Service.
  899        *
  900        * @return ArrayList of String
  901        */
  902       public List<String> getAllRelationIds() {
  903           List<String> result;
  904           synchronized(myRelId2ObjMap) {
  905               result = new ArrayList<String>(myRelId2ObjMap.keySet());
  906           }
  907           return result;
  908       }
  909   
  910       /**
  911        * Checks if given Role can be read in a relation of the given type.
  912        *
  913        * @param roleName  name of role to be checked
  914        * @param relationTypeName  name of the relation type
  915        *
  916        * @return an Integer wrapping an integer corresponding to possible
  917        * problems represented as constants in RoleUnresolved:
  918        * <P>- 0 if role can be read
  919        * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME
  920        * <P>- integer corresponding to RoleStatus.ROLE_NOT_READABLE
  921        *
  922        * @exception IllegalArgumentException  if null parameter
  923        * @exception RelationTypeNotFoundException  if the relation type is not
  924        * known in the Relation Service
  925        */
  926       public Integer checkRoleReading(String roleName,
  927                                       String relationTypeName)
  928           throws IllegalArgumentException,
  929                  RelationTypeNotFoundException {
  930   
  931           if (roleName == null || relationTypeName == null) {
  932               String excMsg = "Invalid parameter.";
  933               throw new IllegalArgumentException(excMsg);
  934           }
  935   
  936           RELATION_LOGGER.entering(RelationService.class.getName(),
  937                   "checkRoleReading", new Object[] {roleName, relationTypeName});
  938   
  939           Integer result;
  940   
  941           // Can throw a RelationTypeNotFoundException
  942           RelationType relType = getRelationType(relationTypeName);
  943   
  944           try {
  945               // Can throw a RoleInfoNotFoundException to be transformed into
  946               // returned value RoleStatus.NO_ROLE_WITH_NAME
  947               RoleInfo roleInfo = relType.getRoleInfo(roleName);
  948   
  949               result =  checkRoleInt(1,
  950                                      roleName,
  951                                      null,
  952                                      roleInfo,
  953                                      false);
  954   
  955           } catch (RoleInfoNotFoundException exc) {
  956               result = Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
  957           }
  958   
  959           RELATION_LOGGER.exiting(RelationService.class.getName(),
  960                   "checkRoleReading");
  961           return result;
  962       }
  963   
  964       /**
  965        * Checks if given Role can be set in a relation of given type.
  966        *
  967        * @param role  role to be checked
  968        * @param relationTypeName  name of relation type
  969        * @param initFlag  flag to specify that the checking is done for the
  970        * initialization of a role, write access shall not be verified.
  971        *
  972        * @return an Integer wrapping an integer corresponding to possible
  973        * problems represented as constants in RoleUnresolved:
  974        * <P>- 0 if role can be set
  975        * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME
  976        * <P>- integer for RoleStatus.ROLE_NOT_WRITABLE
  977        * <P>- integer for RoleStatus.LESS_THAN_MIN_ROLE_DEGREE
  978        * <P>- integer for RoleStatus.MORE_THAN_MAX_ROLE_DEGREE
  979        * <P>- integer for RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS
  980        * <P>- integer for RoleStatus.REF_MBEAN_NOT_REGISTERED
  981        *
  982        * @exception IllegalArgumentException  if null parameter
  983        * @exception RelationTypeNotFoundException  if unknown relation type
  984        */
  985       public Integer checkRoleWriting(Role role,
  986                                       String relationTypeName,
  987                                       Boolean initFlag)
  988           throws IllegalArgumentException,
  989                  RelationTypeNotFoundException {
  990   
  991           if (role == null ||
  992               relationTypeName == null ||
  993               initFlag == null) {
  994               String excMsg = "Invalid parameter.";
  995               throw new IllegalArgumentException(excMsg);
  996           }
  997   
  998           RELATION_LOGGER.entering(RelationService.class.getName(),
  999                   "checkRoleWriting",
 1000                   new Object[] {role, relationTypeName, initFlag});
 1001   
 1002           // Can throw a RelationTypeNotFoundException
 1003           RelationType relType = getRelationType(relationTypeName);
 1004   
 1005           String roleName = role.getRoleName();
 1006           List<ObjectName> roleValue = role.getRoleValue();
 1007           boolean writeChkFlag = true;
 1008           if (initFlag.booleanValue()) {
 1009               writeChkFlag = false;
 1010           }
 1011   
 1012           RoleInfo roleInfo;
 1013           try {
 1014               roleInfo = relType.getRoleInfo(roleName);
 1015           } catch (RoleInfoNotFoundException exc) {
 1016               RELATION_LOGGER.exiting(RelationService.class.getName(),
 1017                       "checkRoleWriting");
 1018               return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
 1019           }
 1020   
 1021           Integer result = checkRoleInt(2,
 1022                                         roleName,
 1023                                         roleValue,
 1024                                         roleInfo,
 1025                                         writeChkFlag);
 1026   
 1027           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1028                   "checkRoleWriting");
 1029           return result;
 1030       }
 1031   
 1032       /**
 1033        * Sends a notification (RelationNotification) for a relation creation.
 1034        * The notification type is:
 1035        * <P>- RelationNotification.RELATION_BASIC_CREATION if the relation is an
 1036        * object internal to the Relation Service
 1037        * <P>- RelationNotification.RELATION_MBEAN_CREATION if the relation is a
 1038        * MBean added as a relation.
 1039        * <P>The source object is the Relation Service itself.
 1040        * <P>It is called in Relation Service createRelation() and
 1041        * addRelation() methods.
 1042        *
 1043        * @param relationId  relation identifier of the updated relation
 1044        *
 1045        * @exception IllegalArgumentException  if null parameter
 1046        * @exception RelationNotFoundException  if there is no relation for given
 1047        * relation id
 1048        */
 1049       public void sendRelationCreationNotification(String relationId)
 1050           throws IllegalArgumentException,
 1051                  RelationNotFoundException {
 1052   
 1053           if (relationId == null) {
 1054               String excMsg = "Invalid parameter.";
 1055               throw new IllegalArgumentException(excMsg);
 1056           }
 1057   
 1058           RELATION_LOGGER.entering(RelationService.class.getName(),
 1059                   "sendRelationCreationNotification", relationId);
 1060   
 1061           // Message
 1062           StringBuilder ntfMsg = new StringBuilder("Creation of relation ");
 1063           ntfMsg.append(relationId);
 1064   
 1065           // Can throw RelationNotFoundException
 1066           sendNotificationInt(1,
 1067                               ntfMsg.toString(),
 1068                               relationId,
 1069                               null,
 1070                               null,
 1071                               null,
 1072                               null);
 1073   
 1074           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1075                   "sendRelationCreationNotification");
 1076           return;
 1077       }
 1078   
 1079       /**
 1080        * Sends a notification (RelationNotification) for a role update in the
 1081        * given relation. The notification type is:
 1082        * <P>- RelationNotification.RELATION_BASIC_UPDATE if the relation is an
 1083        * object internal to the Relation Service
 1084        * <P>- RelationNotification.RELATION_MBEAN_UPDATE if the relation is a
 1085        * MBean added as a relation.
 1086        * <P>The source object is the Relation Service itself.
 1087        * <P>It is called in relation MBean setRole() (for given role) and
 1088        * setRoles() (for each role) methods (implementation provided in
 1089        * RelationSupport class).
 1090        * <P>It is also called in Relation Service setRole() (for given role) and
 1091        * setRoles() (for each role) methods.
 1092        *
 1093        * @param relationId  relation identifier of the updated relation
 1094        * @param newRole  new role (name and new value)
 1095        * @param oldValue  old role value (List of ObjectName objects)
 1096        *
 1097        * @exception IllegalArgumentException  if null parameter
 1098        * @exception RelationNotFoundException  if there is no relation for given
 1099        * relation id
 1100        */
 1101       public void sendRoleUpdateNotification(String relationId,
 1102                                              Role newRole,
 1103                                              List<ObjectName> oldValue)
 1104           throws IllegalArgumentException,
 1105                  RelationNotFoundException {
 1106   
 1107           if (relationId == null ||
 1108               newRole == null ||
 1109               oldValue == null) {
 1110               String excMsg = "Invalid parameter.";
 1111               throw new IllegalArgumentException(excMsg);
 1112           }
 1113   
 1114           if (!(oldValue instanceof ArrayList))
 1115               oldValue = new ArrayList<ObjectName>(oldValue);
 1116   
 1117           RELATION_LOGGER.entering(RelationService.class.getName(),
 1118                   "sendRoleUpdateNotification",
 1119                   new Object[] {relationId, newRole, oldValue});
 1120   
 1121           String roleName = newRole.getRoleName();
 1122           List<ObjectName> newRoleVal = newRole.getRoleValue();
 1123   
 1124           // Message
 1125           String newRoleValString = Role.roleValueToString(newRoleVal);
 1126           String oldRoleValString = Role.roleValueToString(oldValue);
 1127           StringBuilder ntfMsg = new StringBuilder("Value of role ");
 1128           ntfMsg.append(roleName);
 1129           ntfMsg.append(" has changed\nOld value:\n");
 1130           ntfMsg.append(oldRoleValString);
 1131           ntfMsg.append("\nNew value:\n");
 1132           ntfMsg.append(newRoleValString);
 1133   
 1134           // Can throw a RelationNotFoundException
 1135           sendNotificationInt(2,
 1136                               ntfMsg.toString(),
 1137                               relationId,
 1138                               null,
 1139                               roleName,
 1140                               newRoleVal,
 1141                               oldValue);
 1142   
 1143           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1144                   "sendRoleUpdateNotification");
 1145       }
 1146   
 1147       /**
 1148        * Sends a notification (RelationNotification) for a relation removal.
 1149        * The notification type is:
 1150        * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation is an
 1151        * object internal to the Relation Service
 1152        * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is a
 1153        * MBean added as a relation.
 1154        * <P>The source object is the Relation Service itself.
 1155        * <P>It is called in Relation Service removeRelation() method.
 1156        *
 1157        * @param relationId  relation identifier of the updated relation
 1158        * @param unregMBeanList  List of ObjectNames of MBeans expected
 1159        * to be unregistered due to relation removal (can be null)
 1160        *
 1161        * @exception IllegalArgumentException  if null parameter
 1162        * @exception RelationNotFoundException  if there is no relation for given
 1163        * relation id
 1164        */
 1165       public void sendRelationRemovalNotification(String relationId,
 1166                                                   List<ObjectName> unregMBeanList)
 1167           throws IllegalArgumentException,
 1168                  RelationNotFoundException {
 1169   
 1170           if (relationId == null) {
 1171               String excMsg = "Invalid parameter";
 1172               throw new IllegalArgumentException(excMsg);
 1173           }
 1174   
 1175           RELATION_LOGGER.entering(RelationService.class.getName(),
 1176                   "sendRelationRemovalNotification",
 1177                   new Object[] {relationId, unregMBeanList});
 1178   
 1179           // Can throw RelationNotFoundException
 1180           sendNotificationInt(3,
 1181                               "Removal of relation " + relationId,
 1182                               relationId,
 1183                               unregMBeanList,
 1184                               null,
 1185                               null,
 1186                               null);
 1187   
 1188   
 1189           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1190                   "sendRelationRemovalNotification");
 1191           return;
 1192       }
 1193   
 1194       /**
 1195        * Handles update of the Relation Service role map for the update of given
 1196        * role in given relation.
 1197        * <P>It is called in relation MBean setRole() (for given role) and
 1198        * setRoles() (for each role) methods (implementation provided in
 1199        * RelationSupport class).
 1200        * <P>It is also called in Relation Service setRole() (for given role) and
 1201        * setRoles() (for each role) methods.
 1202        * <P>To allow the Relation Service to maintain the consistency (in case
 1203        * of MBean unregistration) and to be able to perform queries, this method
 1204        * must be called when a role is updated.
 1205        *
 1206        * @param relationId  relation identifier of the updated relation
 1207        * @param newRole  new role (name and new value)
 1208        * @param oldValue  old role value (List of ObjectName objects)
 1209        *
 1210        * @exception IllegalArgumentException  if null parameter
 1211        * @exception RelationServiceNotRegisteredException  if the Relation
 1212        * Service is not registered in the MBean Server
 1213        * @exception RelationNotFoundException  if no relation for given id.
 1214        */
 1215       public void updateRoleMap(String relationId,
 1216                                 Role newRole,
 1217                                 List<ObjectName> oldValue)
 1218           throws IllegalArgumentException,
 1219                  RelationServiceNotRegisteredException,
 1220                  RelationNotFoundException {
 1221   
 1222           if (relationId == null ||
 1223               newRole == null ||
 1224               oldValue == null) {
 1225               String excMsg = "Invalid parameter.";
 1226               throw new IllegalArgumentException(excMsg);
 1227           }
 1228   
 1229           RELATION_LOGGER.entering(RelationService.class.getName(),
 1230                   "updateRoleMap", new Object[] {relationId, newRole, oldValue});
 1231   
 1232           // Can throw RelationServiceNotRegisteredException
 1233           isActive();
 1234   
 1235           // Verifies the relation has been added in the Relation Service
 1236           // Can throw a RelationNotFoundException
 1237           Object result = getRelation(relationId);
 1238   
 1239           String roleName = newRole.getRoleName();
 1240           List<ObjectName> newRoleValue = newRole.getRoleValue();
 1241           // Note: no need to test if oldValue not null before cloning,
 1242           //       tested above.
 1243           List<ObjectName> oldRoleValue =
 1244               new ArrayList<ObjectName>(oldValue);
 1245   
 1246           // List of ObjectNames of new referenced MBeans
 1247           List<ObjectName> newRefList = new ArrayList<ObjectName>();
 1248   
 1249           for (ObjectName currObjName : newRoleValue) {
 1250   
 1251               // Checks if this ObjectName was already present in old value
 1252               // Note: use copy (oldRoleValue) instead of original
 1253               //       oldValue to speed up, as oldRoleValue is decreased
 1254               //       by removing unchanged references :)
 1255               int currObjNamePos = oldRoleValue.indexOf(currObjName);
 1256   
 1257               if (currObjNamePos == -1) {
 1258                   // New reference to an ObjectName
 1259   
 1260                   // Stores this reference into map
 1261                   // Returns true if new reference, false if MBean already
 1262                   // referenced
 1263                   boolean isNewFlag = addNewMBeanReference(currObjName,
 1264                                                           relationId,
 1265                                                           roleName);
 1266   
 1267                   if (isNewFlag) {
 1268                       // Adds it into list of new reference
 1269                       newRefList.add(currObjName);
 1270                   }
 1271   
 1272               } else {
 1273                   // MBean was already referenced in old value
 1274   
 1275                   // Removes it from old value (local list) to ignore it when
 1276                   // looking for remove MBean references
 1277                   oldRoleValue.remove(currObjNamePos);
 1278               }
 1279           }
 1280   
 1281           // List of ObjectNames of MBeans no longer referenced
 1282           List<ObjectName> obsRefList = new ArrayList<ObjectName>();
 1283   
 1284           // Each ObjectName remaining in oldRoleValue is an ObjectName no longer
 1285           // referenced in new value
 1286           for (ObjectName currObjName : oldRoleValue) {
 1287               // Removes MBean reference from map
 1288               // Returns true if the MBean is no longer referenced in any
 1289               // relation
 1290               boolean noLongerRefFlag = removeMBeanReference(currObjName,
 1291                                                             relationId,
 1292                                                             roleName,
 1293                                                             false);
 1294   
 1295               if (noLongerRefFlag) {
 1296                   // Adds it into list of references to be removed
 1297                   obsRefList.add(currObjName);
 1298               }
 1299           }
 1300   
 1301           // To avoid having one listener per ObjectName of referenced MBean,
 1302           // and to increase performances, there is only one listener recording
 1303           // all ObjectNames of interest
 1304           updateUnregistrationListener(newRefList, obsRefList);
 1305   
 1306           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1307                   "updateRoleMap");
 1308           return;
 1309       }
 1310   
 1311       /**
 1312        * Removes given relation from the Relation Service.
 1313        * <P>A RelationNotification notification is sent, its type being:
 1314        * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation was
 1315        * only internal to the Relation Service
 1316        * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is
 1317        * registered as an MBean.
 1318        * <P>For MBeans referenced in such relation, nothing will be done,
 1319        *
 1320        * @param relationId  relation id of the relation to be removed
 1321        *
 1322        * @exception RelationServiceNotRegisteredException  if the Relation
 1323        * Service is not registered in the MBean Server
 1324        * @exception IllegalArgumentException  if null parameter
 1325        * @exception RelationNotFoundException  if no relation corresponding to
 1326        * given relation id
 1327        */
 1328       public void removeRelation(String relationId)
 1329           throws RelationServiceNotRegisteredException,
 1330                  IllegalArgumentException,
 1331                  RelationNotFoundException {
 1332   
 1333           // Can throw RelationServiceNotRegisteredException
 1334           isActive();
 1335   
 1336           if (relationId == null) {
 1337               String excMsg = "Invalid parameter.";
 1338               throw new IllegalArgumentException(excMsg);
 1339           }
 1340   
 1341           RELATION_LOGGER.entering(RelationService.class.getName(),
 1342                   "removeRelation", relationId);
 1343   
 1344           // Checks there is a relation with this id
 1345           // Can throw RelationNotFoundException
 1346           Object result = getRelation(relationId);
 1347   
 1348           // Removes it from listener filter
 1349           if (result instanceof ObjectName) {
 1350               List<ObjectName> obsRefList = new ArrayList<ObjectName>();
 1351               obsRefList.add((ObjectName)result);
 1352               // Can throw a RelationServiceNotRegisteredException
 1353               updateUnregistrationListener(null, obsRefList);
 1354           }
 1355   
 1356           // Sends a notification
 1357           // Note: has to be done FIRST as needs the relation to be still in the
 1358           //       Relation Service
 1359           // No RelationNotFoundException as checked above
 1360   
 1361           // Revisit [cebro] Handle CIM "Delete" and "IfDeleted" qualifiers:
 1362           //   deleting the relation can mean to delete referenced MBeans. In
 1363           //   that case, MBeans to be unregistered are put in a list sent along
 1364           //   with the notification below
 1365   
 1366           // Can throw a RelationNotFoundException (but detected above)
 1367           sendRelationRemovalNotification(relationId, null);
 1368   
 1369           // Removes the relation from various internal maps
 1370   
 1371           //  - MBean reference map
 1372           // Retrieves the MBeans referenced in this relation
 1373           // Note: here we cannot use removeMBeanReference() because it would
 1374           //       require to know the MBeans referenced in the relation. For
 1375           //       that it would be necessary to call 'getReferencedMBeans()'
 1376           //       on the relation itself. Ok if it is an internal one, but if
 1377           //       it is an MBean, it is possible it is already unregistered, so
 1378           //       not available through the MBean Server.
 1379           List<ObjectName> refMBeanList = new ArrayList<ObjectName>();
 1380           // List of MBeans no longer referenced in any relation, to be
 1381           // removed fom the map
 1382           List<ObjectName> nonRefObjNameList = new ArrayList<ObjectName>();
 1383   
 1384           synchronized(myRefedMBeanObjName2RelIdsMap) {
 1385   
 1386               for (ObjectName currRefObjName :
 1387                        myRefedMBeanObjName2RelIdsMap.keySet()) {
 1388   
 1389                   // Retrieves relations where the MBean is referenced
 1390                   Map<String,List<String>> relIdMap =
 1391                       myRefedMBeanObjName2RelIdsMap.get(currRefObjName);
 1392   
 1393                   if (relIdMap.containsKey(relationId)) {
 1394                       relIdMap.remove(relationId);
 1395                       refMBeanList.add(currRefObjName);
 1396                   }
 1397   
 1398                   if (relIdMap.isEmpty()) {
 1399                       // MBean no longer referenced
 1400                       // Note: do not remove it here because pointed by the
 1401                       //       iterator!
 1402                       nonRefObjNameList.add(currRefObjName);
 1403                   }
 1404               }
 1405   
 1406               // Cleans MBean reference map by removing MBeans no longer
 1407               // referenced
 1408               for (ObjectName currRefObjName : nonRefObjNameList) {
 1409                   myRefedMBeanObjName2RelIdsMap.remove(currRefObjName);
 1410               }
 1411           }
 1412   
 1413           // - Relation id to object map
 1414           synchronized(myRelId2ObjMap) {
 1415               myRelId2ObjMap.remove(relationId);
 1416           }
 1417   
 1418           if (result instanceof ObjectName) {
 1419               // - ObjectName to relation id map
 1420               synchronized(myRelMBeanObjName2RelIdMap) {
 1421                   myRelMBeanObjName2RelIdMap.remove((ObjectName)result);
 1422               }
 1423           }
 1424   
 1425           // Relation id to relation type name map
 1426           // First retrieves the relation type name
 1427           String relTypeName;
 1428           synchronized(myRelId2RelTypeMap) {
 1429               relTypeName = myRelId2RelTypeMap.get(relationId);
 1430               myRelId2RelTypeMap.remove(relationId);
 1431           }
 1432           // - Relation type name to relation id map
 1433           synchronized(myRelType2RelIdsMap) {
 1434               List<String> relIdList = myRelType2RelIdsMap.get(relTypeName);
 1435               if (relIdList != null) {
 1436                   // Can be null if called from removeRelationType()
 1437                   relIdList.remove(relationId);
 1438                   if (relIdList.isEmpty()) {
 1439                       // No other relation of that type
 1440                       myRelType2RelIdsMap.remove(relTypeName);
 1441                   }
 1442               }
 1443           }
 1444   
 1445           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1446                   "removeRelation");
 1447           return;
 1448       }
 1449   
 1450       /**
 1451        * Purges the relations.
 1452        *
 1453        * <P>Depending on the purgeFlag value, this method is either called
 1454        * automatically when a notification is received for the unregistration of
 1455        * an MBean referenced in a relation (if the flag is set to true), or not
 1456        * (if the flag is set to false).
 1457        * <P>In that case it is up to the user to call it to maintain the
 1458        * consistency of the relations. To be kept in mind that if an MBean is
 1459        * unregistered and the purge not done immediately, if the ObjectName is
 1460        * reused and assigned to another MBean referenced in a relation, calling
 1461        * manually this purgeRelations() method will cause trouble, as will
 1462        * consider the ObjectName as corresponding to the unregistered MBean, not
 1463        * seeing the new one.
 1464        *
 1465        * <P>The behavior depends on the cardinality of the role where the
 1466        * unregistered MBean is referenced:
 1467        * <P>- if removing one MBean reference in the role makes its number of
 1468        * references less than the minimum degree, the relation has to be removed.
 1469        * <P>- if the remaining number of references after removing the MBean
 1470        * reference is still in the cardinality range, keep the relation and
 1471        * update it calling its handleMBeanUnregistration() callback.
 1472        *
 1473        * @exception RelationServiceNotRegisteredException  if the Relation
 1474        * Service is not registered in the MBean Server.
 1475        */
 1476       public void purgeRelations()
 1477           throws RelationServiceNotRegisteredException {
 1478   
 1479           RELATION_LOGGER.entering(RelationService.class.getName(),
 1480                   "purgeRelations");
 1481   
 1482           // Can throw RelationServiceNotRegisteredException
 1483           isActive();
 1484   
 1485           // Revisit [cebro] Handle the CIM "Delete" and "IfDeleted" qualifier:
 1486           //    if the unregistered MBean has the "IfDeleted" qualifier,
 1487           //    possible that the relation itself or other referenced MBeans
 1488           //    have to be removed (then a notification would have to be sent
 1489           //    to inform that they should be unregistered.
 1490   
 1491   
 1492           // Clones the list of notifications to be able to still receive new
 1493           // notifications while proceeding those ones
 1494           List<MBeanServerNotification> localUnregNtfList;
 1495           synchronized(myUnregNtfList) {
 1496               localUnregNtfList =
 1497                   new ArrayList<MBeanServerNotification>(myUnregNtfList);
 1498               // Resets list
 1499               myUnregNtfList = new ArrayList<MBeanServerNotification>();
 1500           }
 1501   
 1502   
 1503           // Updates the listener filter to avoid receiving notifications for
 1504           // those MBeans again
 1505           // Makes also a local "myRefedMBeanObjName2RelIdsMap" map, mapping
 1506           // ObjectName -> relId -> roles, to remove the MBean from the global
 1507           // map
 1508           // List of references to be removed from the listener filter
 1509           List<ObjectName> obsRefList = new ArrayList<ObjectName>();
 1510           // Map including ObjectNames for unregistered MBeans, with
 1511           // referencing relation ids and roles
 1512           Map<ObjectName,Map<String,List<String>>> localMBean2RelIdMap =
 1513               new HashMap<ObjectName,Map<String,List<String>>>();
 1514   
 1515           synchronized(myRefedMBeanObjName2RelIdsMap) {
 1516               for (MBeanServerNotification currNtf : localUnregNtfList) {
 1517   
 1518                   ObjectName unregMBeanName = currNtf.getMBeanName();
 1519   
 1520                   // Adds the unregsitered MBean in the list of references to
 1521                   // remove from the listener filter
 1522                   obsRefList.add(unregMBeanName);
 1523   
 1524                   // Retrieves the associated map of relation ids and roles
 1525                   Map<String,List<String>> relIdMap =
 1526                       myRefedMBeanObjName2RelIdsMap.get(unregMBeanName);
 1527                   localMBean2RelIdMap.put(unregMBeanName, relIdMap);
 1528   
 1529                   myRefedMBeanObjName2RelIdsMap.remove(unregMBeanName);
 1530               }
 1531           }
 1532   
 1533           // Updates the listener
 1534           // Can throw RelationServiceNotRegisteredException
 1535           updateUnregistrationListener(null, obsRefList);
 1536   
 1537           for (MBeanServerNotification currNtf : localUnregNtfList) {
 1538   
 1539               ObjectName unregMBeanName = currNtf.getMBeanName();
 1540   
 1541               // Retrieves the relations where the MBean is referenced
 1542               Map<String,List<String>> localRelIdMap =
 1543                       localMBean2RelIdMap.get(unregMBeanName);
 1544   
 1545               // List of relation ids where the unregistered MBean is
 1546               // referenced
 1547               for (Map.Entry<String,List<String>> currRel :
 1548                           localRelIdMap.entrySet()) {
 1549                   final String currRelId = currRel.getKey();
 1550                   // List of roles of the relation where the MBean is
 1551                   // referenced
 1552                   List<String> localRoleNameList = currRel.getValue();
 1553   
 1554                   // Checks if the relation has to be removed or not,
 1555                   // regarding expected minimum role cardinality and current
 1556                   // number of references after removal of the current one
 1557                   // If the relation is kept, calls
 1558                   // handleMBeanUnregistration() callback of the relation to
 1559                   // update it
 1560                   //
 1561                   // Can throw RelationServiceNotRegisteredException
 1562                   //
 1563                   // Shall not throw RelationNotFoundException,
 1564                   // RoleNotFoundException, MBeanException
 1565                   try {
 1566                       handleReferenceUnregistration(currRelId,
 1567                                                     unregMBeanName,
 1568                                                     localRoleNameList);
 1569                   } catch (RelationNotFoundException exc1) {
 1570                       throw new RuntimeException(exc1.getMessage());
 1571                   } catch (RoleNotFoundException exc2) {
 1572                       throw new RuntimeException(exc2.getMessage());
 1573                   }
 1574               }
 1575           }
 1576   
 1577           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1578                   "purgeRelations");
 1579           return;
 1580       }
 1581   
 1582       /**
 1583        * Retrieves the relations where a given MBean is referenced.
 1584        * <P>This corresponds to the CIM "References" and "ReferenceNames"
 1585        * operations.
 1586        *
 1587        * @param mbeanName  ObjectName of MBean
 1588        * @param relationTypeName  can be null; if specified, only the relations
 1589        * of that type will be considered in the search. Else all relation types
 1590        * are considered.
 1591        * @param roleName  can be null; if specified, only the relations
 1592        * where the MBean is referenced in that role will be returned. Else all
 1593        * roles are considered.
 1594        *
 1595        * @return an HashMap, where the keys are the relation ids of the relations
 1596        * where the MBean is referenced, and the value is, for each key,
 1597        * an ArrayList of role names (as an MBean can be referenced in several
 1598        * roles in the same relation).
 1599        *
 1600        * @exception IllegalArgumentException  if null parameter
 1601        */
 1602       public Map<String,List<String>>
 1603           findReferencingRelations(ObjectName mbeanName,
 1604                                    String relationTypeName,
 1605                                    String roleName)
 1606               throws IllegalArgumentException {
 1607   
 1608           if (mbeanName == null) {
 1609               String excMsg = "Invalid parameter.";
 1610               throw new IllegalArgumentException(excMsg);
 1611           }
 1612   
 1613           RELATION_LOGGER.entering(RelationService.class.getName(),
 1614                   "findReferencingRelations",
 1615                   new Object[] {mbeanName, relationTypeName, roleName});
 1616   
 1617           Map<String,List<String>> result = new HashMap<String,List<String>>();
 1618   
 1619           synchronized(myRefedMBeanObjName2RelIdsMap) {
 1620   
 1621               // Retrieves the relations referencing the MBean
 1622               Map<String,List<String>> relId2RoleNamesMap =
 1623                   myRefedMBeanObjName2RelIdsMap.get(mbeanName);
 1624   
 1625               if (relId2RoleNamesMap != null) {
 1626   
 1627                   // Relation Ids where the MBean is referenced
 1628                   Set<String> allRelIdSet = relId2RoleNamesMap.keySet();
 1629   
 1630                   // List of relation ids of interest regarding the selected
 1631                   // relation type
 1632                   List<String> relIdList;
 1633                   if (relationTypeName == null) {
 1634                       // Considers all relations
 1635                       relIdList = new ArrayList<String>(allRelIdSet);
 1636   
 1637                   } else {
 1638   
 1639                       relIdList = new ArrayList<String>();
 1640   
 1641                       // Considers only the relation ids for relations of given
 1642                       // type
 1643                       for (String currRelId : allRelIdSet) {
 1644   
 1645                           // Retrieves its relation type
 1646                           String currRelTypeName;
 1647                           synchronized(myRelId2RelTypeMap) {
 1648                               currRelTypeName =
 1649                                   myRelId2RelTypeMap.get(currRelId);
 1650                           }
 1651   
 1652                           if (currRelTypeName.equals(relationTypeName)) {
 1653   
 1654                               relIdList.add(currRelId);
 1655   
 1656                           }
 1657                       }
 1658                   }
 1659   
 1660                   // Now looks at the roles where the MBean is expected to be
 1661                   // referenced
 1662   
 1663                   for (String currRelId : relIdList) {
 1664                       // Retrieves list of role names where the MBean is
 1665                       // referenced
 1666                       List<String> currRoleNameList =
 1667                           relId2RoleNamesMap.get(currRelId);
 1668   
 1669                       if (roleName == null) {
 1670                           // All roles to be considered
 1671                           // Note: no need to test if list not null before
 1672                           //       cloning, MUST be not null else bug :(
 1673                           result.put(currRelId,
 1674                                      new ArrayList<String>(currRoleNameList));
 1675   
 1676                       }  else if (currRoleNameList.contains(roleName)) {
 1677                           // Filters only the relations where the MBean is
 1678                           // referenced in // given role
 1679                           List<String> dummyList = new ArrayList<String>();
 1680                           dummyList.add(roleName);
 1681                           result.put(currRelId, dummyList);
 1682                       }
 1683                   }
 1684               }
 1685           }
 1686   
 1687           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1688                   "findReferencingRelations");
 1689           return result;
 1690       }
 1691   
 1692       /**
 1693        * Retrieves the MBeans associated to given one in a relation.
 1694        * <P>This corresponds to CIM Associators and AssociatorNames operations.
 1695        *
 1696        * @param mbeanName  ObjectName of MBean
 1697        * @param relationTypeName  can be null; if specified, only the relations
 1698        * of that type will be considered in the search. Else all
 1699        * relation types are considered.
 1700        * @param roleName  can be null; if specified, only the relations
 1701        * where the MBean is referenced in that role will be considered. Else all
 1702        * roles are considered.
 1703        *
 1704        * @return an HashMap, where the keys are the ObjectNames of the MBeans
 1705        * associated to given MBean, and the value is, for each key, an ArrayList
 1706        * of the relation ids of the relations where the key MBean is
 1707        * associated to given one (as they can be associated in several different
 1708        * relations).
 1709        *
 1710        * @exception IllegalArgumentException  if null parameter
 1711        */
 1712       public Map<ObjectName,List<String>>
 1713           findAssociatedMBeans(ObjectName mbeanName,
 1714                                String relationTypeName,
 1715                                String roleName)
 1716               throws IllegalArgumentException {
 1717   
 1718           if (mbeanName == null) {
 1719               String excMsg = "Invalid parameter.";
 1720               throw new IllegalArgumentException(excMsg);
 1721           }
 1722   
 1723           RELATION_LOGGER.entering(RelationService.class.getName(),
 1724                   "findAssociatedMBeans",
 1725                   new Object[] {mbeanName, relationTypeName, roleName});
 1726   
 1727           // Retrieves the map <relation id> -> <role names> for those
 1728           // criterias
 1729           Map<String,List<String>> relId2RoleNamesMap =
 1730               findReferencingRelations(mbeanName,
 1731                                        relationTypeName,
 1732                                        roleName);
 1733   
 1734           Map<ObjectName,List<String>> result =
 1735               new HashMap<ObjectName,List<String>>();
 1736   
 1737           for (String currRelId : relId2RoleNamesMap.keySet()) {
 1738   
 1739               // Retrieves ObjectNames of MBeans referenced in this relation
 1740               //
 1741               // Shall not throw a RelationNotFoundException if incorrect status
 1742               // of maps :(
 1743               Map<ObjectName,List<String>> objName2RoleNamesMap;
 1744               try {
 1745                   objName2RoleNamesMap = getReferencedMBeans(currRelId);
 1746               } catch (RelationNotFoundException exc) {
 1747                   throw new RuntimeException(exc.getMessage());
 1748               }
 1749   
 1750               // For each MBean associated to given one in a relation, adds the
 1751               // association <ObjectName> -> <relation id> into result map
 1752               for (ObjectName currObjName : objName2RoleNamesMap.keySet()) {
 1753   
 1754                   if (!(currObjName.equals(mbeanName))) {
 1755   
 1756                       // Sees if this MBean is already associated to the given
 1757                       // one in another relation
 1758                       List<String> currRelIdList = result.get(currObjName);
 1759                       if (currRelIdList == null) {
 1760   
 1761                           currRelIdList = new ArrayList<String>();
 1762                           currRelIdList.add(currRelId);
 1763                           result.put(currObjName, currRelIdList);
 1764   
 1765                       } else {
 1766                           currRelIdList.add(currRelId);
 1767                       }
 1768                   }
 1769               }
 1770           }
 1771   
 1772           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1773                   "findAssociatedMBeans");
 1774           return result;
 1775       }
 1776   
 1777       /**
 1778        * Returns the relation ids for relations of the given type.
 1779        *
 1780        * @param relationTypeName  relation type name
 1781        *
 1782        * @return an ArrayList of relation ids.
 1783        *
 1784        * @exception IllegalArgumentException  if null parameter
 1785        * @exception RelationTypeNotFoundException  if there is no relation type
 1786        * with that name.
 1787        */
 1788       public List<String> findRelationsOfType(String relationTypeName)
 1789           throws IllegalArgumentException,
 1790                  RelationTypeNotFoundException {
 1791   
 1792           if (relationTypeName == null) {
 1793               String excMsg = "Invalid parameter.";
 1794               throw new IllegalArgumentException(excMsg);
 1795           }
 1796   
 1797           RELATION_LOGGER.entering(RelationService.class.getName(),
 1798                   "findRelationsOfType");
 1799   
 1800           // Can throw RelationTypeNotFoundException
 1801           RelationType relType = getRelationType(relationTypeName);
 1802   
 1803           List<String> result;
 1804           synchronized(myRelType2RelIdsMap) {
 1805               List<String> result1 = myRelType2RelIdsMap.get(relationTypeName);
 1806               if (result1 == null)
 1807                   result = new ArrayList<String>();
 1808               else
 1809                   result = new ArrayList<String>(result1);
 1810           }
 1811   
 1812           RELATION_LOGGER.exiting(RelationService.class.getName(),
 1813                   "findRelationsOfType");
 1814           return result;
 1815       }
 1816   
 1817       /**
 1818        * Retrieves role value for given role name in given relation.
 1819        *
 1820        * @param relationId  relation id
 1821        * @param roleName  name of role
 1822        *
 1823        * @return the ArrayList of ObjectName objects being the role value
 1824        *
 1825        * @exception RelationServiceNotRegisteredException  if the Relation
 1826        * Service is not registered
 1827        * @exception IllegalArgumentException  if null parameter
 1828        * @exception RelationNotFoundException  if no relation with given id
 1829        * @exception RoleNotFoundException  if:
 1830        * <P>- there is no role with given name
 1831        * <P>or
 1832        * <P>- the role is not readable.
 1833        *
 1834        * @see #setRole
 1835        */
 1836       public List<ObjectName> getRole(String relationId,
 1837                                       String roleName)
 1838           throws RelationServiceNotRegisteredException,
 1839                  IllegalArgumentException,
 1840                  RelationNotFoundException,
 1841                  RoleNotFoundException {
 1842   
 1843           if (relationId == null || roleName == null) {
 1844               String excMsg = "Invalid parameter.";
 1845               throw new IllegalArgumentException(excMsg);
 1846           }
 1847   
 1848           RELATION_LOGGER.entering(RelationService.class.getName(),
 1849                   "getRole", new Object[] {relationId, roleName});
 1850   
 1851           // Can throw RelationServiceNotRegisteredException
 1852           isActive();
 1853   
 1854           // Can throw a RelationNotFoundException
 1855           Object relObj = getRelation(relationId);
 1856   
 1857           List<ObjectName> result;
 1858   
 1859           if (relObj instanceof RelationSupport) {
 1860               // Internal relation
 1861               // Can throw RoleNotFoundException
 1862               result = cast(
 1863                   ((RelationSupport)relObj).getRoleInt(roleName,
 1864                                                        true,
 1865                                                        this,
 1866                                                        false));
 1867   
 1868           } else {
 1869               // Relation MBean
 1870               Object[] params = new Object[1];
 1871               params[0] = roleName;
 1872               String[] signature = new String[1];
 1873               signature[0] = "java.lang.String";
 1874               // Can throw MBeanException wrapping a RoleNotFoundException:
 1875               // throw wrapped exception
 1876               //
 1877               // Shall not throw InstanceNotFoundException or ReflectionException
 1878               try {
 1879                   List<ObjectName> invokeResult = cast(
 1880                       myMBeanServer.invoke(((ObjectName)relObj),
 1881                                            "getRole",
 1882                                            params,
 1883                                            signature));
 1884                   if (invokeResult == null || invokeResult instanceof ArrayList)
 1885                       result = invokeResult;
 1886                   else
 1887                       result = new ArrayList<ObjectName>(invokeResult);
 1888               } catch (InstanceNotFoundException exc1) {
 1889                   throw new RuntimeException(exc1.getMessage());
 1890               } catch (ReflectionException exc2) {
 1891                   throw new RuntimeException(exc2.getMessage());
 1892               } catch (MBeanException exc3) {
 1893                   Exception wrappedExc = exc3.getTargetException();
 1894                   if (wrappedExc instanceof RoleNotFoundException) {
 1895                       throw ((RoleNotFoundException)wrappedExc);
 1896                   } else {
 1897                       throw new RuntimeException(wrappedExc.getMessage());
 1898                   }
 1899               }
 1900           }
 1901   
 1902           RELATION_LOGGER.exiting(RelationService.class.getName(), "getRole");
 1903           return result;
 1904       }
 1905   
 1906       /**
 1907        * Retrieves values of roles with given names in given relation.
 1908        *
 1909        * @param relationId  relation id
 1910        * @param roleNameArray  array of names of roles to be retrieved
 1911        *
 1912        * @return a RoleResult object, including a RoleList (for roles
 1913        * successfully retrieved) and a RoleUnresolvedList (for roles not
 1914        * retrieved).
 1915        *
 1916        * @exception RelationServiceNotRegisteredException  if the Relation
 1917        * Service is not registered in the MBean Server
 1918        * @exception IllegalArgumentException  if null parameter
 1919        * @exception RelationNotFoundException  if no relation with given id
 1920        *
 1921        * @see #setRoles
 1922        */
 1923       public RoleResult getRoles(String relationId,
 1924                                  String[] roleNameArray)
 1925           throws RelationServiceNotRegisteredException,
 1926                  IllegalArgumentException,
 1927                  RelationNotFoundException {
 1928   
 1929           if (relationId == null || roleNameArray == null) {
 1930               String excMsg = "Invalid parameter.";
 1931               throw new IllegalArgumentException(excMsg);
 1932           }
 1933   
 1934           RELATION_LOGGER.entering(RelationService.class.getName(),
 1935                   "getRoles", relationId);
 1936   
 1937           // Can throw RelationServiceNotRegisteredException
 1938           isActive();
 1939   
 1940           // Can throw a RelationNotFoundException
 1941           Object relObj = getRelation(relationId);
 1942   
 1943           RoleResult result;
 1944   
 1945           if (relObj instanceof RelationSupport) {
 1946               // Internal relation
 1947               result = ((RelationSupport)relObj).getRolesInt(roleNameArray,
 1948                                                           true,
 1949                                                           this);
 1950           } else {
 1951               // Relation MBean
 1952               Object[] params = new Object[1];
 1953               params[0] = roleNameArray;
 1954               String[] signature = new String[1];
 1955               try {
 1956                   signature[0] = (roleNameArray.getClass()).getName();
 1957               } catch (Exception exc) {
 1958                   // OK : This is an array of java.lang.String
 1959                   //      so this should never happen...
 1960               }
 1961               // Shall not throw InstanceNotFoundException, ReflectionException
 1962               // or MBeanException
 1963               try {
 1964                   result = (RoleResult)
 1965                       (myMBeanServer.invoke(((ObjectName)relObj),
 1966                                             "getRoles",
 1967                                             params,
 1968                                             signature));
 1969               } catch (InstanceNotFoundException exc1) {
 1970                   throw new RuntimeException(exc1.getMessage());
 1971               } catch (ReflectionException exc2) {
 1972                   throw new RuntimeException(exc2.getMessage());
 1973               } catch (MBeanException exc3) {
 1974                   throw new
 1975                       RuntimeException((exc3.getTargetException()).getMessage());
 1976               }
 1977           }
 1978   
 1979           RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoles");
 1980           return result;
 1981       }
 1982   
 1983       /**
 1984        * Returns all roles present in the relation.
 1985        *
 1986        * @param relationId  relation id
 1987        *
 1988        * @return a RoleResult object, including a RoleList (for roles
 1989        * successfully retrieved) and a RoleUnresolvedList (for roles not
 1990        * readable).
 1991        *
 1992        * @exception IllegalArgumentException  if null parameter
 1993        * @exception RelationNotFoundException  if no relation for given id
 1994        * @exception RelationServiceNotRegisteredException  if the Relation
 1995        * Service is not registered in the MBean Server
 1996        */
 1997       public RoleResult getAllRoles(String relationId)
 1998           throws IllegalArgumentException,
 1999                  RelationNotFoundException,
 2000                  RelationServiceNotRegisteredException {
 2001   
 2002           if (relationId == null) {
 2003               String excMsg = "Invalid parameter.";
 2004               throw new IllegalArgumentException(excMsg);
 2005           }
 2006   
 2007           RELATION_LOGGER.entering(RelationService.class.getName(),
 2008                   "getRoles", relationId);
 2009   
 2010           // Can throw a RelationNotFoundException
 2011           Object relObj = getRelation(relationId);
 2012   
 2013           RoleResult result;
 2014   
 2015           if (relObj instanceof RelationSupport) {
 2016               // Internal relation
 2017               result = ((RelationSupport)relObj).getAllRolesInt(true, this);
 2018   
 2019           } else {
 2020               // Relation MBean
 2021               // Shall not throw any Exception
 2022               try {
 2023                   result = (RoleResult)
 2024                       (myMBeanServer.getAttribute(((ObjectName)relObj),
 2025                                                   "AllRoles"));
 2026               } catch (Exception exc) {
 2027                   throw new RuntimeException(exc.getMessage());
 2028               }
 2029           }
 2030   
 2031           RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoles");
 2032           return result;
 2033       }
 2034   
 2035       /**
 2036        * Retrieves the number of MBeans currently referenced in the given role.
 2037        *
 2038        * @param relationId  relation id
 2039        * @param roleName  name of role
 2040        *
 2041        * @return the number of currently referenced MBeans in that role
 2042        *
 2043        * @exception IllegalArgumentException  if null parameter
 2044        * @exception RelationNotFoundException  if no relation with given id
 2045        * @exception RoleNotFoundException  if there is no role with given name
 2046        */
 2047       public Integer getRoleCardinality(String relationId,
 2048                                         String roleName)
 2049           throws IllegalArgumentException,
 2050                  RelationNotFoundException,
 2051                  RoleNotFoundException {
 2052   
 2053           if (relationId == null || roleName == null) {
 2054               String excMsg = "Invalid parameter.";
 2055               throw new IllegalArgumentException(excMsg);
 2056           }
 2057   
 2058           RELATION_LOGGER.entering(RelationService.class.getName(),
 2059                   "getRoleCardinality", new Object[] {relationId, roleName});
 2060   
 2061           // Can throw a RelationNotFoundException
 2062           Object relObj = getRelation(relationId);
 2063   
 2064           Integer result;
 2065   
 2066           if (relObj instanceof RelationSupport) {
 2067               // Internal relation
 2068               // Can throw RoleNotFoundException
 2069               result = ((RelationSupport)relObj).getRoleCardinality(roleName);
 2070   
 2071           } else {
 2072               // Relation MBean
 2073               Object[] params = new Object[1];
 2074               params[0] = roleName;
 2075               String[] signature = new String[1];
 2076               signature[0] = "java.lang.String";
 2077               // Can throw MBeanException wrapping RoleNotFoundException:
 2078               // throw wrapped exception
 2079               //
 2080               // Shall not throw InstanceNotFoundException or ReflectionException
 2081               try {
 2082                   result = (Integer)
 2083                       (myMBeanServer.invoke(((ObjectName)relObj),
 2084                                             "getRoleCardinality",
 2085                                             params,
 2086                                             signature));
 2087               } catch (InstanceNotFoundException exc1) {
 2088                   throw new RuntimeException(exc1.getMessage());
 2089               } catch (ReflectionException exc2) {
 2090                   throw new RuntimeException(exc2.getMessage());
 2091               } catch (MBeanException exc3) {
 2092                   Exception wrappedExc = exc3.getTargetException();
 2093                   if (wrappedExc instanceof RoleNotFoundException) {
 2094                       throw ((RoleNotFoundException)wrappedExc);
 2095                   } else {
 2096                       throw new RuntimeException(wrappedExc.getMessage());
 2097                   }
 2098               }
 2099           }
 2100   
 2101           RELATION_LOGGER.exiting(RelationService.class.getName(),
 2102                   "getRoleCardinality");
 2103           return result;
 2104       }
 2105   
 2106       /**
 2107        * Sets the given role in given relation.
 2108        * <P>Will check the role according to its corresponding role definition
 2109        * provided in relation's relation type
 2110        * <P>The Relation Service will keep track of the change to keep the
 2111        * consistency of relations by handling referenced MBean unregistrations.
 2112        *
 2113        * @param relationId  relation id
 2114        * @param role  role to be set (name and new value)
 2115        *
 2116        * @exception RelationServiceNotRegisteredException  if the Relation
 2117        * Service is not registered in the MBean Server
 2118        * @exception IllegalArgumentException  if null parameter
 2119        * @exception RelationNotFoundException  if no relation with given id
 2120        * @exception RoleNotFoundException  if the role does not exist or is not
 2121        * writable
 2122        * @exception InvalidRoleValueException  if value provided for role is not
 2123        * valid:
 2124        * <P>- the number of referenced MBeans in given value is less than
 2125        * expected minimum degree
 2126        * <P>or
 2127        * <P>- the number of referenced MBeans in provided value exceeds expected
 2128        * maximum degree
 2129        * <P>or
 2130        * <P>- one referenced MBean in the value is not an Object of the MBean
 2131        * class expected for that role
 2132        * <P>or
 2133        * <P>- an MBean provided for that role does not exist
 2134        *
 2135        * @see #getRole
 2136        */
 2137       public void setRole(String relationId,
 2138                           Role role)
 2139           throws RelationServiceNotRegisteredException,
 2140                  IllegalArgumentException,
 2141                  RelationNotFoundException,
 2142                  RoleNotFoundException,
 2143                  InvalidRoleValueException {
 2144   
 2145           if (relationId == null || role == null) {
 2146               String excMsg = "Invalid parameter.";
 2147               throw new IllegalArgumentException(excMsg);
 2148           }
 2149   
 2150           RELATION_LOGGER.entering(RelationService.class.getName(),
 2151                   "setRole", new Object[] {relationId, role});
 2152   
 2153           // Can throw RelationServiceNotRegisteredException
 2154           isActive();
 2155   
 2156           // Can throw a RelationNotFoundException
 2157           Object relObj = getRelation(relationId);
 2158   
 2159           if (relObj instanceof RelationSupport) {
 2160               // Internal relation
 2161               // Can throw RoleNotFoundException,
 2162               // InvalidRoleValueException and
 2163               // RelationServiceNotRegisteredException
 2164               //
 2165               // Shall not throw RelationTypeNotFoundException
 2166               // (as relation exists in the RS, its relation type is known)
 2167               try {
 2168                   ((RelationSupport)relObj).setRoleInt(role,
 2169                                                     true,
 2170                                                     this,
 2171                                                     false);
 2172   
 2173               } catch (RelationTypeNotFoundException exc) {
 2174                   throw new RuntimeException(exc.getMessage());
 2175               }
 2176   
 2177           } else {
 2178               // Relation MBean
 2179               Object[] params = new Object[1];
 2180               params[0] = role;
 2181               String[] signature = new String[1];
 2182               signature[0] = "javax.management.relation.Role";
 2183               // Can throw MBeanException wrapping RoleNotFoundException,
 2184               // InvalidRoleValueException
 2185               //
 2186               // Shall not MBeanException wrapping an MBeanException wrapping
 2187               // RelationTypeNotFoundException, or ReflectionException, or
 2188               // InstanceNotFoundException
 2189               try {
 2190                   myMBeanServer.setAttribute(((ObjectName)relObj),
 2191                                              new Attribute("Role", role));
 2192   
 2193               } catch (InstanceNotFoundException exc1) {
 2194                   throw new RuntimeException(exc1.getMessage());
 2195               } catch (ReflectionException exc3) {
 2196                   throw new RuntimeException(exc3.getMessage());
 2197               } catch (MBeanException exc2) {
 2198                   Exception wrappedExc = exc2.getTargetException();
 2199                   if (wrappedExc instanceof RoleNotFoundException) {
 2200                       throw ((RoleNotFoundException)wrappedExc);
 2201                   } else if (wrappedExc instanceof InvalidRoleValueException) {
 2202                       throw ((InvalidRoleValueException)wrappedExc);
 2203                   } else {
 2204                       throw new RuntimeException(wrappedExc.getMessage());
 2205   
 2206                   }
 2207               } catch (AttributeNotFoundException exc4) {
 2208                 throw new RuntimeException(exc4.getMessage());
 2209               } catch (InvalidAttributeValueException exc5) {
 2210                 throw new RuntimeException(exc5.getMessage());
 2211               }
 2212           }
 2213   
 2214           RELATION_LOGGER.exiting(RelationService.class.getName(), "setRole");
 2215           return;
 2216       }
 2217   
 2218       /**
 2219        * Sets the given roles in given relation.
 2220        * <P>Will check the role according to its corresponding role definition
 2221        * provided in relation's relation type
 2222        * <P>The Relation Service keeps track of the changes to keep the
 2223        * consistency of relations by handling referenced MBean unregistrations.
 2224        *
 2225        * @param relationId  relation id
 2226        * @param roleList  list of roles to be set
 2227        *
 2228        * @return a RoleResult object, including a RoleList (for roles
 2229        * successfully set) and a RoleUnresolvedList (for roles not
 2230        * set).
 2231        *
 2232        * @exception RelationServiceNotRegisteredException  if the Relation
 2233        * Service is not registered in the MBean Server
 2234        * @exception IllegalArgumentException  if null parameter
 2235        * @exception RelationNotFoundException  if no relation with given id
 2236        *
 2237        * @see #getRoles
 2238        */
 2239       public RoleResult setRoles(String relationId,
 2240                                  RoleList roleList)
 2241           throws RelationServiceNotRegisteredException,
 2242                  IllegalArgumentException,
 2243                  RelationNotFoundException {
 2244   
 2245           if (relationId == null || roleList == null) {
 2246               String excMsg = "Invalid parameter.";
 2247               throw new IllegalArgumentException(excMsg);
 2248           }
 2249   
 2250           RELATION_LOGGER.entering(RelationService.class.getName(),
 2251                   "setRoles", new Object[] {relationId, roleList});
 2252   
 2253           // Can throw RelationServiceNotRegisteredException
 2254           isActive();
 2255   
 2256           // Can throw a RelationNotFoundException
 2257           Object relObj = getRelation(relationId);
 2258   
 2259           RoleResult result;
 2260   
 2261           if (relObj instanceof RelationSupport) {
 2262               // Internal relation
 2263               // Can throw RelationServiceNotRegisteredException
 2264               //
 2265               // Shall not throw RelationTypeNotFoundException (as relation is
 2266               // known, its relation type exists)
 2267               try {
 2268                   result = ((RelationSupport)relObj).setRolesInt(roleList,
 2269                                                               true,
 2270                                                               this);
 2271               } catch (RelationTypeNotFoundException exc) {
 2272                   throw new RuntimeException(exc.getMessage());
 2273               }
 2274   
 2275           } else {
 2276               // Relation MBean
 2277               Object[] params = new Object[1];
 2278               params[0] = roleList;
 2279               String[] signature = new String[1];
 2280               signature[0] = "javax.management.relation.RoleList";
 2281               // Shall not throw InstanceNotFoundException or an MBeanException
 2282               // or ReflectionException
 2283               try {
 2284                   result = (RoleResult)
 2285                       (myMBeanServer.invoke(((ObjectName)relObj),
 2286                                             "setRoles",
 2287                                             params,
 2288                                             signature));
 2289               } catch (InstanceNotFoundException exc1) {
 2290                   throw new RuntimeException(exc1.getMessage());
 2291               } catch (ReflectionException exc3) {
 2292                   throw new RuntimeException(exc3.get