src/java.management/share/classes/javax/management/relation/RelationService.java
changeset 47216 71c04702a3d5
parent 43235 da1786d695b6
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2000, 2017, Oracle and/or its affiliates. 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * 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.lang.System.Logger.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 final 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 deregistrations
       
   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.log(Level.TRACE, "ENTRY");
       
   161 
       
   162         setPurgeFlag(immediatePurgeFlag);
       
   163 
       
   164         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   165         return;
       
   166     }
       
   167 
       
   168     /**
       
   169      * Checks if the Relation Service is active.
       
   170      * Current condition is that the Relation Service must be registered in the
       
   171      * MBean Server
       
   172      *
       
   173      * @exception RelationServiceNotRegisteredException  if it is not
       
   174      * registered
       
   175      */
       
   176     public void isActive()
       
   177         throws RelationServiceNotRegisteredException {
       
   178         if (myMBeanServer == null) {
       
   179             // MBean Server not set by preRegister(): relation service not
       
   180             // registered
       
   181             String excMsg =
       
   182                 "Relation Service not registered in the MBean Server.";
       
   183             throw new RelationServiceNotRegisteredException(excMsg);
       
   184         }
       
   185         return;
       
   186     }
       
   187 
       
   188     //
       
   189     // MBeanRegistration interface
       
   190     //
       
   191 
       
   192     // Pre-registration: retrieves its ObjectName and MBean Server
       
   193     //
       
   194     // No exception thrown.
       
   195     public ObjectName preRegister(MBeanServer server,
       
   196                                   ObjectName name)
       
   197         throws Exception {
       
   198 
       
   199         myMBeanServer = server;
       
   200         myObjName = name;
       
   201         return name;
       
   202     }
       
   203 
       
   204     // Post-registration: does nothing
       
   205     public void postRegister(Boolean registrationDone) {
       
   206         return;
       
   207     }
       
   208 
       
   209     // Pre-unregistration: does nothing
       
   210     public void preDeregister()
       
   211         throws Exception {
       
   212         return;
       
   213     }
       
   214 
       
   215     // Post-unregistration: does nothing
       
   216     public void postDeregister() {
       
   217         return;
       
   218     }
       
   219 
       
   220     //
       
   221     // Accessors
       
   222     //
       
   223 
       
   224     /**
       
   225      * Returns the flag to indicate if when a notification is received for the
       
   226      * unregistration of an MBean referenced in a relation, if an immediate
       
   227      * "purge" of the relations (look for the relations no longer valid)
       
   228      * has to be performed , or if that will be performed only when the
       
   229      * purgeRelations method will be explicitly called.
       
   230      * <P>true is immediate purge.
       
   231      *
       
   232      * @return true if purges are automatic.
       
   233      *
       
   234      * @see #setPurgeFlag
       
   235      */
       
   236     public boolean getPurgeFlag() {
       
   237         return myPurgeFlag;
       
   238     }
       
   239 
       
   240     /**
       
   241      * Sets the flag to indicate if when a notification is received for the
       
   242      * unregistration of an MBean referenced in a relation, if an immediate
       
   243      * "purge" of the relations (look for the relations no longer valid)
       
   244      * has to be performed , or if that will be performed only when the
       
   245      * purgeRelations method will be explicitly called.
       
   246      * <P>true is immediate purge.
       
   247      *
       
   248      * @param purgeFlag  flag
       
   249      *
       
   250      * @see #getPurgeFlag
       
   251      */
       
   252     public void setPurgeFlag(boolean purgeFlag) {
       
   253 
       
   254         myPurgeFlag = purgeFlag;
       
   255         return;
       
   256     }
       
   257 
       
   258     //
       
   259     // Relation type handling
       
   260     //
       
   261 
       
   262     /**
       
   263      * Creates a relation type (a RelationTypeSupport object) with given
       
   264      * role infos (provided by the RoleInfo objects), and adds it in the
       
   265      * Relation Service.
       
   266      *
       
   267      * @param relationTypeName  name of the relation type
       
   268      * @param roleInfoArray  array of role infos
       
   269      *
       
   270      * @exception IllegalArgumentException  if null parameter
       
   271      * @exception InvalidRelationTypeException  If:
       
   272      * <P>- there is already a relation type with that name
       
   273      * <P>- the same name has been used for two different role infos
       
   274      * <P>- no role info provided
       
   275      * <P>- one null role info provided
       
   276      */
       
   277     public void createRelationType(String relationTypeName,
       
   278                                    RoleInfo[] roleInfoArray)
       
   279         throws IllegalArgumentException,
       
   280                InvalidRelationTypeException {
       
   281 
       
   282         if (relationTypeName == null || roleInfoArray == null) {
       
   283             String excMsg = "Invalid parameter.";
       
   284             throw new IllegalArgumentException(excMsg);
       
   285         }
       
   286 
       
   287         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationTypeName);
       
   288 
       
   289         // Can throw an InvalidRelationTypeException
       
   290         RelationType relType =
       
   291             new RelationTypeSupport(relationTypeName, roleInfoArray);
       
   292 
       
   293         addRelationTypeInt(relType);
       
   294 
       
   295         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   296         return;
       
   297     }
       
   298 
       
   299     /**
       
   300      * Adds given object as a relation type. The object is expected to
       
   301      * implement the RelationType interface.
       
   302      *
       
   303      * @param relationTypeObj  relation type object (implementing the
       
   304      * RelationType interface)
       
   305      *
       
   306      * @exception IllegalArgumentException  if null parameter or if
       
   307      * {@link RelationType#getRelationTypeName
       
   308      * relationTypeObj.getRelationTypeName()} returns null.
       
   309      * @exception InvalidRelationTypeException  if:
       
   310      * <P>- the same name has been used for two different roles
       
   311      * <P>- no role info provided
       
   312      * <P>- one null role info provided
       
   313      * <P>- there is already a relation type with that name
       
   314      */
       
   315     public void addRelationType(RelationType relationTypeObj)
       
   316         throws IllegalArgumentException,
       
   317                InvalidRelationTypeException {
       
   318 
       
   319         if (relationTypeObj == null) {
       
   320             String excMsg = "Invalid parameter.";
       
   321             throw new IllegalArgumentException(excMsg);
       
   322         }
       
   323 
       
   324         RELATION_LOGGER.log(Level.TRACE, "ENTRY");
       
   325 
       
   326         // Checks the role infos
       
   327         List<RoleInfo> roleInfoList = relationTypeObj.getRoleInfos();
       
   328         if (roleInfoList == null) {
       
   329             String excMsg = "No role info provided.";
       
   330             throw new InvalidRelationTypeException(excMsg);
       
   331         }
       
   332 
       
   333         RoleInfo[] roleInfoArray = new RoleInfo[roleInfoList.size()];
       
   334         int i = 0;
       
   335         for (RoleInfo currRoleInfo : roleInfoList) {
       
   336             roleInfoArray[i] = currRoleInfo;
       
   337             i++;
       
   338         }
       
   339         // Can throw InvalidRelationTypeException
       
   340         RelationTypeSupport.checkRoleInfos(roleInfoArray);
       
   341 
       
   342         addRelationTypeInt(relationTypeObj);
       
   343 
       
   344         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   345         return;
       
   346      }
       
   347 
       
   348     /**
       
   349      * Retrieves names of all known relation types.
       
   350      *
       
   351      * @return ArrayList of relation type names (Strings)
       
   352      */
       
   353     public List<String> getAllRelationTypeNames() {
       
   354         ArrayList<String> result;
       
   355         synchronized(myRelType2ObjMap) {
       
   356             result = new ArrayList<String>(myRelType2ObjMap.keySet());
       
   357         }
       
   358         return result;
       
   359     }
       
   360 
       
   361     /**
       
   362      * Retrieves list of role infos (RoleInfo objects) of a given relation
       
   363      * type.
       
   364      *
       
   365      * @param relationTypeName  name of relation type
       
   366      *
       
   367      * @return ArrayList of RoleInfo.
       
   368      *
       
   369      * @exception IllegalArgumentException  if null parameter
       
   370      * @exception RelationTypeNotFoundException  if there is no relation type
       
   371      * with that name.
       
   372      */
       
   373     public List<RoleInfo> getRoleInfos(String relationTypeName)
       
   374         throws IllegalArgumentException,
       
   375                RelationTypeNotFoundException {
       
   376 
       
   377         if (relationTypeName == null) {
       
   378             String excMsg = "Invalid parameter.";
       
   379             throw new IllegalArgumentException(excMsg);
       
   380         }
       
   381 
       
   382         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationTypeName);
       
   383 
       
   384         // Can throw a RelationTypeNotFoundException
       
   385         RelationType relType = getRelationType(relationTypeName);
       
   386 
       
   387         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   388         return relType.getRoleInfos();
       
   389     }
       
   390 
       
   391     /**
       
   392      * Retrieves role info for given role name of a given relation type.
       
   393      *
       
   394      * @param relationTypeName  name of relation type
       
   395      * @param roleInfoName  name of role
       
   396      *
       
   397      * @return RoleInfo object.
       
   398      *
       
   399      * @exception IllegalArgumentException  if null parameter
       
   400      * @exception RelationTypeNotFoundException  if the relation type is not
       
   401      * known in the Relation Service
       
   402      * @exception RoleInfoNotFoundException  if the role is not part of the
       
   403      * relation type.
       
   404      */
       
   405     public RoleInfo getRoleInfo(String relationTypeName,
       
   406                                 String roleInfoName)
       
   407         throws IllegalArgumentException,
       
   408                RelationTypeNotFoundException,
       
   409                RoleInfoNotFoundException {
       
   410 
       
   411         if (relationTypeName == null || roleInfoName == null) {
       
   412             String excMsg = "Invalid parameter.";
       
   413             throw new IllegalArgumentException(excMsg);
       
   414         }
       
   415 
       
   416         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
   417                             relationTypeName, roleInfoName);
       
   418 
       
   419         // Can throw a RelationTypeNotFoundException
       
   420         RelationType relType = getRelationType(relationTypeName);
       
   421 
       
   422         // Can throw a RoleInfoNotFoundException
       
   423         RoleInfo roleInfo = relType.getRoleInfo(roleInfoName);
       
   424 
       
   425         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   426         return roleInfo;
       
   427     }
       
   428 
       
   429     /**
       
   430      * Removes given relation type from Relation Service.
       
   431      * <P>The relation objects of that type will be removed from the
       
   432      * Relation Service.
       
   433      *
       
   434      * @param relationTypeName  name of the relation type to be removed
       
   435      *
       
   436      * @exception RelationServiceNotRegisteredException  if the Relation
       
   437      * Service is not registered in the MBean Server
       
   438      * @exception IllegalArgumentException  if null parameter
       
   439      * @exception RelationTypeNotFoundException  If there is no relation type
       
   440      * with that name
       
   441      */
       
   442     public void removeRelationType(String relationTypeName)
       
   443         throws RelationServiceNotRegisteredException,
       
   444                IllegalArgumentException,
       
   445                RelationTypeNotFoundException {
       
   446 
       
   447         // Can throw RelationServiceNotRegisteredException
       
   448         isActive();
       
   449 
       
   450         if (relationTypeName == null) {
       
   451             String excMsg = "Invalid parameter.";
       
   452             throw new IllegalArgumentException(excMsg);
       
   453         }
       
   454 
       
   455         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationTypeName);
       
   456 
       
   457         // Checks if the relation type to be removed exists
       
   458         // Can throw a RelationTypeNotFoundException
       
   459         RelationType relType = getRelationType(relationTypeName);
       
   460 
       
   461         // Retrieves the relation ids for relations of that type
       
   462         List<String> relIdList = null;
       
   463         synchronized(myRelType2RelIdsMap) {
       
   464             // Note: take a copy of the list as it is a part of a map that
       
   465             //       will be updated by removeRelation() below.
       
   466             List<String> relIdList1 =
       
   467                 myRelType2RelIdsMap.get(relationTypeName);
       
   468             if (relIdList1 != null) {
       
   469                 relIdList = new ArrayList<String>(relIdList1);
       
   470             }
       
   471         }
       
   472 
       
   473         // Removes the relation type from all maps
       
   474         synchronized(myRelType2ObjMap) {
       
   475             myRelType2ObjMap.remove(relationTypeName);
       
   476         }
       
   477         synchronized(myRelType2RelIdsMap) {
       
   478             myRelType2RelIdsMap.remove(relationTypeName);
       
   479         }
       
   480 
       
   481         // Removes all relations of that type
       
   482         if (relIdList != null) {
       
   483             for (String currRelId : relIdList) {
       
   484                 // Note: will remove it from myRelId2RelTypeMap :)
       
   485                 //
       
   486                 // Can throw RelationServiceNotRegisteredException (detected
       
   487                 // above)
       
   488                 // Shall not throw a RelationNotFoundException
       
   489                 try {
       
   490                     removeRelation(currRelId);
       
   491                 } catch (RelationNotFoundException exc1) {
       
   492                     throw new RuntimeException(exc1.getMessage());
       
   493                 }
       
   494             }
       
   495         }
       
   496 
       
   497         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   498         return;
       
   499     }
       
   500 
       
   501     //
       
   502     // Relation handling
       
   503     //
       
   504 
       
   505     /**
       
   506      * Creates a simple relation (represented by a RelationSupport object) of
       
   507      * given relation type, and adds it in the Relation Service.
       
   508      * <P>Roles are initialized according to the role list provided in
       
   509      * parameter. The ones not initialized in this way are set to an empty
       
   510      * ArrayList of ObjectNames.
       
   511      * <P>A RelationNotification, with type RELATION_BASIC_CREATION, is sent.
       
   512      *
       
   513      * @param relationId  relation identifier, to identify uniquely the relation
       
   514      * inside the Relation Service
       
   515      * @param relationTypeName  name of the relation type (has to be created
       
   516      * in the Relation Service)
       
   517      * @param roleList  role list to initialize roles of the relation (can
       
   518      * be null).
       
   519      *
       
   520      * @exception RelationServiceNotRegisteredException  if the Relation
       
   521      * Service is not registered in the MBean Server
       
   522      * @exception IllegalArgumentException  if null parameter, except the role
       
   523      * list which can be null if no role initialization
       
   524      * @exception RoleNotFoundException  if a value is provided for a role
       
   525      * that does not exist in the relation type
       
   526      * @exception InvalidRelationIdException  if relation id already used
       
   527      * @exception RelationTypeNotFoundException  if relation type not known in
       
   528      * Relation Service
       
   529      * @exception InvalidRoleValueException if:
       
   530      * <P>- the same role name is used for two different roles
       
   531      * <P>- the number of referenced MBeans in given value is less than
       
   532      * expected minimum degree
       
   533      * <P>- the number of referenced MBeans in provided value exceeds expected
       
   534      * maximum degree
       
   535      * <P>- one referenced MBean in the value is not an Object of the MBean
       
   536      * class expected for that role
       
   537      * <P>- an MBean provided for that role does not exist
       
   538      */
       
   539     public void createRelation(String relationId,
       
   540                                String relationTypeName,
       
   541                                RoleList roleList)
       
   542         throws RelationServiceNotRegisteredException,
       
   543                IllegalArgumentException,
       
   544                RoleNotFoundException,
       
   545                InvalidRelationIdException,
       
   546                RelationTypeNotFoundException,
       
   547                InvalidRoleValueException {
       
   548 
       
   549         // Can throw RelationServiceNotRegisteredException
       
   550         isActive();
       
   551 
       
   552         if (relationId == null ||
       
   553             relationTypeName == null) {
       
   554             String excMsg = "Invalid parameter.";
       
   555             throw new IllegalArgumentException(excMsg);
       
   556         }
       
   557 
       
   558         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
   559                             relationId, relationTypeName, roleList);
       
   560 
       
   561         // Creates RelationSupport object
       
   562         // Can throw InvalidRoleValueException
       
   563         RelationSupport relObj = new RelationSupport(relationId,
       
   564                                                myObjName,
       
   565                                                relationTypeName,
       
   566                                                roleList);
       
   567 
       
   568         // Adds relation object as a relation into the Relation Service
       
   569         // Can throw RoleNotFoundException, InvalidRelationId,
       
   570         // RelationTypeNotFoundException, InvalidRoleValueException
       
   571         //
       
   572         // Cannot throw MBeanException
       
   573         addRelationInt(true,
       
   574                        relObj,
       
   575                        null,
       
   576                        relationId,
       
   577                        relationTypeName,
       
   578                        roleList);
       
   579         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   580         return;
       
   581     }
       
   582 
       
   583     /**
       
   584      * Adds an MBean created by the user (and registered by him in the MBean
       
   585      * Server) as a relation in the Relation Service.
       
   586      * <P>To be added as a relation, the MBean must conform to the
       
   587      * following:
       
   588      * <P>- implement the Relation interface
       
   589      * <P>- have for RelationService ObjectName the ObjectName of current
       
   590      * Relation Service
       
   591      * <P>- have a relation id unique and unused in current Relation Service
       
   592      * <P>- have for relation type a relation type created in the Relation
       
   593      * Service
       
   594      * <P>- have roles conforming to the role info provided in the relation
       
   595      * type.
       
   596      *
       
   597      * @param relationObjectName  ObjectName of the relation MBean to be added.
       
   598      *
       
   599      * @exception IllegalArgumentException  if null parameter
       
   600      * @exception RelationServiceNotRegisteredException  if the Relation
       
   601      * Service is not registered in the MBean Server
       
   602      * @exception NoSuchMethodException  If the MBean does not implement the
       
   603      * Relation interface
       
   604      * @exception InvalidRelationIdException  if:
       
   605      * <P>- no relation identifier in MBean
       
   606      * <P>- the relation identifier is already used in the Relation Service
       
   607      * @exception InstanceNotFoundException  if the MBean for given ObjectName
       
   608      * has not been registered
       
   609      * @exception InvalidRelationServiceException  if:
       
   610      * <P>- no Relation Service name in MBean
       
   611      * <P>- the Relation Service name in the MBean is not the one of the
       
   612      * current Relation Service
       
   613      * @exception RelationTypeNotFoundException  if:
       
   614      * <P>- no relation type name in MBean
       
   615      * <P>- the relation type name in MBean does not correspond to a relation
       
   616      * type created in the Relation Service
       
   617      * @exception InvalidRoleValueException  if:
       
   618      * <P>- the number of referenced MBeans in a role is less than
       
   619      * expected minimum degree
       
   620      * <P>- the number of referenced MBeans in a role exceeds expected
       
   621      * maximum degree
       
   622      * <P>- one referenced MBean in the value is not an Object of the MBean
       
   623      * class expected for that role
       
   624      * <P>- an MBean provided for a role does not exist
       
   625      * @exception RoleNotFoundException  if a value is provided for a role
       
   626      * that does not exist in the relation type
       
   627      */
       
   628     public void addRelation(ObjectName relationObjectName)
       
   629         throws IllegalArgumentException,
       
   630                RelationServiceNotRegisteredException,
       
   631                NoSuchMethodException,
       
   632                InvalidRelationIdException,
       
   633                InstanceNotFoundException,
       
   634                InvalidRelationServiceException,
       
   635                RelationTypeNotFoundException,
       
   636                RoleNotFoundException,
       
   637                InvalidRoleValueException {
       
   638 
       
   639         if (relationObjectName == null) {
       
   640             String excMsg = "Invalid parameter.";
       
   641             throw new IllegalArgumentException(excMsg);
       
   642         }
       
   643 
       
   644         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationObjectName);
       
   645 
       
   646         // Can throw RelationServiceNotRegisteredException
       
   647         isActive();
       
   648 
       
   649         // Checks that the relation MBean implements the Relation interface.
       
   650         // It will also check that the provided ObjectName corresponds to a
       
   651         // registered MBean (else will throw an InstanceNotFoundException)
       
   652         if ((!(myMBeanServer.isInstanceOf(relationObjectName, "javax.management.relation.Relation")))) {
       
   653             String excMsg = "This MBean does not implement the Relation interface.";
       
   654             throw new NoSuchMethodException(excMsg);
       
   655         }
       
   656         // Checks there is a relation id in the relation MBean (its uniqueness
       
   657         // is checked in addRelationInt())
       
   658         // Can throw InstanceNotFoundException (but detected above)
       
   659         // No MBeanException as no exception raised by this method, and no
       
   660         // ReflectionException
       
   661         String relId;
       
   662         try {
       
   663             relId = (String)(myMBeanServer.getAttribute(relationObjectName,
       
   664                                                         "RelationId"));
       
   665 
       
   666         } catch (MBeanException exc1) {
       
   667             throw new RuntimeException(
       
   668                                      (exc1.getTargetException()).getMessage());
       
   669         } catch (ReflectionException exc2) {
       
   670             throw new RuntimeException(exc2.getMessage());
       
   671         } catch (AttributeNotFoundException exc3) {
       
   672             throw new RuntimeException(exc3.getMessage());
       
   673         }
       
   674 
       
   675         if (relId == null) {
       
   676             String excMsg = "This MBean does not provide a relation id.";
       
   677             throw new InvalidRelationIdException(excMsg);
       
   678         }
       
   679         // Checks that the Relation Service where the relation MBean is
       
   680         // expected to be added is the current one
       
   681         // Can throw InstanceNotFoundException (but detected above)
       
   682         // No MBeanException as no exception raised by this method, no
       
   683         // ReflectionException
       
   684         ObjectName relServObjName;
       
   685         try {
       
   686             relServObjName = (ObjectName)
       
   687                 (myMBeanServer.getAttribute(relationObjectName,
       
   688                                             "RelationServiceName"));
       
   689 
       
   690         } catch (MBeanException exc1) {
       
   691             throw new RuntimeException(
       
   692                                      (exc1.getTargetException()).getMessage());
       
   693         } catch (ReflectionException exc2) {
       
   694             throw new RuntimeException(exc2.getMessage());
       
   695         } catch (AttributeNotFoundException exc3) {
       
   696             throw new RuntimeException(exc3.getMessage());
       
   697         }
       
   698 
       
   699         boolean badRelServFlag = false;
       
   700         if (relServObjName == null) {
       
   701             badRelServFlag = true;
       
   702 
       
   703         } else if (!(relServObjName.equals(myObjName))) {
       
   704             badRelServFlag = true;
       
   705         }
       
   706         if (badRelServFlag) {
       
   707             String excMsg = "The Relation Service referenced in the MBean is not the current one.";
       
   708             throw new InvalidRelationServiceException(excMsg);
       
   709         }
       
   710         // Checks that a relation type has been specified for the relation
       
   711         // Can throw InstanceNotFoundException (but detected above)
       
   712         // No MBeanException as no exception raised by this method, no
       
   713         // ReflectionException
       
   714         String relTypeName;
       
   715         try {
       
   716             relTypeName = (String)(myMBeanServer.getAttribute(relationObjectName,
       
   717                                                               "RelationTypeName"));
       
   718 
       
   719         } catch (MBeanException exc1) {
       
   720             throw new RuntimeException(
       
   721                                      (exc1.getTargetException()).getMessage());
       
   722         }catch (ReflectionException exc2) {
       
   723             throw new RuntimeException(exc2.getMessage());
       
   724         } catch (AttributeNotFoundException exc3) {
       
   725             throw new RuntimeException(exc3.getMessage());
       
   726         }
       
   727         if (relTypeName == null) {
       
   728             String excMsg = "No relation type provided.";
       
   729             throw new RelationTypeNotFoundException(excMsg);
       
   730         }
       
   731         // Retrieves all roles without considering read mode
       
   732         // Can throw InstanceNotFoundException (but detected above)
       
   733         // No MBeanException as no exception raised by this method, no
       
   734         // ReflectionException
       
   735         RoleList roleList;
       
   736         try {
       
   737             roleList = (RoleList)(myMBeanServer.invoke(relationObjectName,
       
   738                                                        "retrieveAllRoles",
       
   739                                                        null,
       
   740                                                        null));
       
   741         } catch (MBeanException exc1) {
       
   742             throw new RuntimeException(
       
   743                                      (exc1.getTargetException()).getMessage());
       
   744         } catch (ReflectionException exc2) {
       
   745             throw new RuntimeException(exc2.getMessage());
       
   746         }
       
   747 
       
   748         // Can throw RoleNotFoundException, InvalidRelationIdException,
       
   749         // RelationTypeNotFoundException, InvalidRoleValueException
       
   750         addRelationInt(false,
       
   751                        null,
       
   752                        relationObjectName,
       
   753                        relId,
       
   754                        relTypeName,
       
   755                        roleList);
       
   756         // Adds relation MBean ObjectName in map
       
   757         synchronized(myRelMBeanObjName2RelIdMap) {
       
   758             myRelMBeanObjName2RelIdMap.put(relationObjectName, relId);
       
   759         }
       
   760 
       
   761         // Updates flag to specify that the relation is managed by the Relation
       
   762         // Service
       
   763         // This flag and setter are inherited from RelationSupport and not parts
       
   764         // of the Relation interface, so may be not supported.
       
   765         try {
       
   766             myMBeanServer.setAttribute(relationObjectName,
       
   767                                        new Attribute(
       
   768                                          "RelationServiceManagementFlag",
       
   769                                          Boolean.TRUE));
       
   770         } catch (Exception exc) {
       
   771             // OK : The flag is not supported.
       
   772         }
       
   773 
       
   774         // Updates listener information to received notification for
       
   775         // unregistration of this MBean
       
   776         List<ObjectName> newRefList = new ArrayList<ObjectName>();
       
   777         newRefList.add(relationObjectName);
       
   778         updateUnregistrationListener(newRefList, null);
       
   779 
       
   780         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   781         return;
       
   782     }
       
   783 
       
   784     /**
       
   785      * If the relation is represented by an MBean (created by the user and
       
   786      * added as a relation in the Relation Service), returns the ObjectName of
       
   787      * the MBean.
       
   788      *
       
   789      * @param relationId  relation id identifying the relation
       
   790      *
       
   791      * @return ObjectName of the corresponding relation MBean, or null if
       
   792      * the relation is not an MBean.
       
   793      *
       
   794      * @exception IllegalArgumentException  if null parameter
       
   795      * @exception RelationNotFoundException there is no relation associated
       
   796      * to that id
       
   797      */
       
   798     public ObjectName isRelationMBean(String relationId)
       
   799         throws IllegalArgumentException,
       
   800                RelationNotFoundException{
       
   801 
       
   802         if (relationId == null) {
       
   803             String excMsg = "Invalid parameter.";
       
   804             throw new IllegalArgumentException(excMsg);
       
   805         }
       
   806 
       
   807         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
   808 
       
   809         // Can throw RelationNotFoundException
       
   810         Object result = getRelation(relationId);
       
   811         if (result instanceof ObjectName) {
       
   812             return ((ObjectName)result);
       
   813         } else {
       
   814             return null;
       
   815         }
       
   816     }
       
   817 
       
   818     /**
       
   819      * Returns the relation id associated to the given ObjectName if the
       
   820      * MBean has been added as a relation in the Relation Service.
       
   821      *
       
   822      * @param objectName  ObjectName of supposed relation
       
   823      *
       
   824      * @return relation id (String) or null (if the ObjectName is not a
       
   825      * relation handled by the Relation Service)
       
   826      *
       
   827      * @exception IllegalArgumentException  if null parameter
       
   828      */
       
   829     public String isRelation(ObjectName objectName)
       
   830         throws IllegalArgumentException {
       
   831 
       
   832         if (objectName == null) {
       
   833             String excMsg = "Invalid parameter.";
       
   834             throw new IllegalArgumentException(excMsg);
       
   835         }
       
   836 
       
   837         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", objectName);
       
   838 
       
   839         String result = null;
       
   840         synchronized(myRelMBeanObjName2RelIdMap) {
       
   841             String relId = myRelMBeanObjName2RelIdMap.get(objectName);
       
   842             if (relId != null) {
       
   843                 result = relId;
       
   844             }
       
   845         }
       
   846         return result;
       
   847     }
       
   848 
       
   849     /**
       
   850      * Checks if there is a relation identified in Relation Service with given
       
   851      * relation id.
       
   852      *
       
   853      * @param relationId  relation id identifying the relation
       
   854      *
       
   855      * @return boolean: true if there is a relation, false else
       
   856      *
       
   857      * @exception IllegalArgumentException  if null parameter
       
   858      */
       
   859     public Boolean hasRelation(String relationId)
       
   860         throws IllegalArgumentException {
       
   861 
       
   862         if (relationId == null) {
       
   863             String excMsg = "Invalid parameter.";
       
   864             throw new IllegalArgumentException(excMsg);
       
   865         }
       
   866 
       
   867         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
   868 
       
   869         try {
       
   870             // Can throw RelationNotFoundException
       
   871             Object result = getRelation(relationId);
       
   872             return true;
       
   873         } catch (RelationNotFoundException exc) {
       
   874             return false;
       
   875         }
       
   876     }
       
   877 
       
   878     /**
       
   879      * Returns all the relation ids for all the relations handled by the
       
   880      * Relation Service.
       
   881      *
       
   882      * @return ArrayList of String
       
   883      */
       
   884     public List<String> getAllRelationIds() {
       
   885         List<String> result;
       
   886         synchronized(myRelId2ObjMap) {
       
   887             result = new ArrayList<String>(myRelId2ObjMap.keySet());
       
   888         }
       
   889         return result;
       
   890     }
       
   891 
       
   892     /**
       
   893      * Checks if given Role can be read in a relation of the given type.
       
   894      *
       
   895      * @param roleName  name of role to be checked
       
   896      * @param relationTypeName  name of the relation type
       
   897      *
       
   898      * @return an Integer wrapping an integer corresponding to possible
       
   899      * problems represented as constants in RoleUnresolved:
       
   900      * <P>- 0 if role can be read
       
   901      * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME
       
   902      * <P>- integer corresponding to RoleStatus.ROLE_NOT_READABLE
       
   903      *
       
   904      * @exception IllegalArgumentException  if null parameter
       
   905      * @exception RelationTypeNotFoundException  if the relation type is not
       
   906      * known in the Relation Service
       
   907      */
       
   908     public Integer checkRoleReading(String roleName,
       
   909                                     String relationTypeName)
       
   910         throws IllegalArgumentException,
       
   911                RelationTypeNotFoundException {
       
   912 
       
   913         if (roleName == null || relationTypeName == null) {
       
   914             String excMsg = "Invalid parameter.";
       
   915             throw new IllegalArgumentException(excMsg);
       
   916         }
       
   917 
       
   918         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
   919                             roleName, relationTypeName);
       
   920 
       
   921         Integer result;
       
   922 
       
   923         // Can throw a RelationTypeNotFoundException
       
   924         RelationType relType = getRelationType(relationTypeName);
       
   925 
       
   926         try {
       
   927             // Can throw a RoleInfoNotFoundException to be transformed into
       
   928             // returned value RoleStatus.NO_ROLE_WITH_NAME
       
   929             RoleInfo roleInfo = relType.getRoleInfo(roleName);
       
   930 
       
   931             result =  checkRoleInt(1,
       
   932                                    roleName,
       
   933                                    null,
       
   934                                    roleInfo,
       
   935                                    false);
       
   936 
       
   937         } catch (RoleInfoNotFoundException exc) {
       
   938             result = Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
       
   939         }
       
   940 
       
   941         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   942         return result;
       
   943     }
       
   944 
       
   945     /**
       
   946      * Checks if given Role can be set in a relation of given type.
       
   947      *
       
   948      * @param role  role to be checked
       
   949      * @param relationTypeName  name of relation type
       
   950      * @param initFlag  flag to specify that the checking is done for the
       
   951      * initialization of a role, write access shall not be verified.
       
   952      *
       
   953      * @return an Integer wrapping an integer corresponding to possible
       
   954      * problems represented as constants in RoleUnresolved:
       
   955      * <P>- 0 if role can be set
       
   956      * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME
       
   957      * <P>- integer for RoleStatus.ROLE_NOT_WRITABLE
       
   958      * <P>- integer for RoleStatus.LESS_THAN_MIN_ROLE_DEGREE
       
   959      * <P>- integer for RoleStatus.MORE_THAN_MAX_ROLE_DEGREE
       
   960      * <P>- integer for RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS
       
   961      * <P>- integer for RoleStatus.REF_MBEAN_NOT_REGISTERED
       
   962      *
       
   963      * @exception IllegalArgumentException  if null parameter
       
   964      * @exception RelationTypeNotFoundException  if unknown relation type
       
   965      */
       
   966     public Integer checkRoleWriting(Role role,
       
   967                                     String relationTypeName,
       
   968                                     Boolean initFlag)
       
   969         throws IllegalArgumentException,
       
   970                RelationTypeNotFoundException {
       
   971 
       
   972         if (role == null ||
       
   973             relationTypeName == null ||
       
   974             initFlag == null) {
       
   975             String excMsg = "Invalid parameter.";
       
   976             throw new IllegalArgumentException(excMsg);
       
   977         }
       
   978 
       
   979         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
   980                             role, relationTypeName, initFlag);
       
   981 
       
   982         // Can throw a RelationTypeNotFoundException
       
   983         RelationType relType = getRelationType(relationTypeName);
       
   984 
       
   985         String roleName = role.getRoleName();
       
   986         List<ObjectName> roleValue = role.getRoleValue();
       
   987         boolean writeChkFlag = true;
       
   988         if (initFlag.booleanValue()) {
       
   989             writeChkFlag = false;
       
   990         }
       
   991 
       
   992         RoleInfo roleInfo;
       
   993         try {
       
   994             roleInfo = relType.getRoleInfo(roleName);
       
   995         } catch (RoleInfoNotFoundException exc) {
       
   996             RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
   997             return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
       
   998         }
       
   999 
       
  1000         Integer result = checkRoleInt(2,
       
  1001                                       roleName,
       
  1002                                       roleValue,
       
  1003                                       roleInfo,
       
  1004                                       writeChkFlag);
       
  1005 
       
  1006         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1007         return result;
       
  1008     }
       
  1009 
       
  1010     /**
       
  1011      * Sends a notification (RelationNotification) for a relation creation.
       
  1012      * The notification type is:
       
  1013      * <P>- RelationNotification.RELATION_BASIC_CREATION if the relation is an
       
  1014      * object internal to the Relation Service
       
  1015      * <P>- RelationNotification.RELATION_MBEAN_CREATION if the relation is a
       
  1016      * MBean added as a relation.
       
  1017      * <P>The source object is the Relation Service itself.
       
  1018      * <P>It is called in Relation Service createRelation() and
       
  1019      * addRelation() methods.
       
  1020      *
       
  1021      * @param relationId  relation identifier of the updated relation
       
  1022      *
       
  1023      * @exception IllegalArgumentException  if null parameter
       
  1024      * @exception RelationNotFoundException  if there is no relation for given
       
  1025      * relation id
       
  1026      */
       
  1027     public void sendRelationCreationNotification(String relationId)
       
  1028         throws IllegalArgumentException,
       
  1029                RelationNotFoundException {
       
  1030 
       
  1031         if (relationId == null) {
       
  1032             String excMsg = "Invalid parameter.";
       
  1033             throw new IllegalArgumentException(excMsg);
       
  1034         }
       
  1035 
       
  1036         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
  1037 
       
  1038         // Message
       
  1039         StringBuilder ntfMsg = new StringBuilder("Creation of relation ");
       
  1040         ntfMsg.append(relationId);
       
  1041 
       
  1042         // Can throw RelationNotFoundException
       
  1043         sendNotificationInt(1,
       
  1044                             ntfMsg.toString(),
       
  1045                             relationId,
       
  1046                             null,
       
  1047                             null,
       
  1048                             null,
       
  1049                             null);
       
  1050 
       
  1051         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1052         return;
       
  1053     }
       
  1054 
       
  1055     /**
       
  1056      * Sends a notification (RelationNotification) for a role update in the
       
  1057      * given relation. The notification type is:
       
  1058      * <P>- RelationNotification.RELATION_BASIC_UPDATE if the relation is an
       
  1059      * object internal to the Relation Service
       
  1060      * <P>- RelationNotification.RELATION_MBEAN_UPDATE if the relation is a
       
  1061      * MBean added as a relation.
       
  1062      * <P>The source object is the Relation Service itself.
       
  1063      * <P>It is called in relation MBean setRole() (for given role) and
       
  1064      * setRoles() (for each role) methods (implementation provided in
       
  1065      * RelationSupport class).
       
  1066      * <P>It is also called in Relation Service setRole() (for given role) and
       
  1067      * setRoles() (for each role) methods.
       
  1068      *
       
  1069      * @param relationId  relation identifier of the updated relation
       
  1070      * @param newRole  new role (name and new value)
       
  1071      * @param oldValue  old role value (List of ObjectName objects)
       
  1072      *
       
  1073      * @exception IllegalArgumentException  if null parameter
       
  1074      * @exception RelationNotFoundException  if there is no relation for given
       
  1075      * relation id
       
  1076      */
       
  1077     public void sendRoleUpdateNotification(String relationId,
       
  1078                                            Role newRole,
       
  1079                                            List<ObjectName> oldValue)
       
  1080         throws IllegalArgumentException,
       
  1081                RelationNotFoundException {
       
  1082 
       
  1083         if (relationId == null ||
       
  1084             newRole == null ||
       
  1085             oldValue == null) {
       
  1086             String excMsg = "Invalid parameter.";
       
  1087             throw new IllegalArgumentException(excMsg);
       
  1088         }
       
  1089 
       
  1090         if (!(oldValue instanceof ArrayList<?>))
       
  1091             oldValue = new ArrayList<ObjectName>(oldValue);
       
  1092 
       
  1093         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
  1094                             relationId, newRole, oldValue);
       
  1095 
       
  1096         String roleName = newRole.getRoleName();
       
  1097         List<ObjectName> newRoleVal = newRole.getRoleValue();
       
  1098 
       
  1099         // Message
       
  1100         String newRoleValString = Role.roleValueToString(newRoleVal);
       
  1101         String oldRoleValString = Role.roleValueToString(oldValue);
       
  1102         StringBuilder ntfMsg = new StringBuilder("Value of role ");
       
  1103         ntfMsg.append(roleName);
       
  1104         ntfMsg.append(" has changed\nOld value:\n");
       
  1105         ntfMsg.append(oldRoleValString);
       
  1106         ntfMsg.append("\nNew value:\n");
       
  1107         ntfMsg.append(newRoleValString);
       
  1108 
       
  1109         // Can throw a RelationNotFoundException
       
  1110         sendNotificationInt(2,
       
  1111                             ntfMsg.toString(),
       
  1112                             relationId,
       
  1113                             null,
       
  1114                             roleName,
       
  1115                             newRoleVal,
       
  1116                             oldValue);
       
  1117 
       
  1118         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1119     }
       
  1120 
       
  1121     /**
       
  1122      * Sends a notification (RelationNotification) for a relation removal.
       
  1123      * The notification type is:
       
  1124      * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation is an
       
  1125      * object internal to the Relation Service
       
  1126      * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is a
       
  1127      * MBean added as a relation.
       
  1128      * <P>The source object is the Relation Service itself.
       
  1129      * <P>It is called in Relation Service removeRelation() method.
       
  1130      *
       
  1131      * @param relationId  relation identifier of the updated relation
       
  1132      * @param unregMBeanList  List of ObjectNames of MBeans expected
       
  1133      * to be unregistered due to relation removal (can be null)
       
  1134      *
       
  1135      * @exception IllegalArgumentException  if null parameter
       
  1136      * @exception RelationNotFoundException  if there is no relation for given
       
  1137      * relation id
       
  1138      */
       
  1139     public void sendRelationRemovalNotification(String relationId,
       
  1140                                                 List<ObjectName> unregMBeanList)
       
  1141         throws IllegalArgumentException,
       
  1142                RelationNotFoundException {
       
  1143 
       
  1144         if (relationId == null) {
       
  1145             String excMsg = "Invalid parameter";
       
  1146             throw new IllegalArgumentException(excMsg);
       
  1147         }
       
  1148 
       
  1149         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
  1150                             relationId, unregMBeanList);
       
  1151 
       
  1152         // Can throw RelationNotFoundException
       
  1153         sendNotificationInt(3,
       
  1154                             "Removal of relation " + relationId,
       
  1155                             relationId,
       
  1156                             unregMBeanList,
       
  1157                             null,
       
  1158                             null,
       
  1159                             null);
       
  1160 
       
  1161 
       
  1162         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1163         return;
       
  1164     }
       
  1165 
       
  1166     /**
       
  1167      * Handles update of the Relation Service role map for the update of given
       
  1168      * role in given relation.
       
  1169      * <P>It is called in relation MBean setRole() (for given role) and
       
  1170      * setRoles() (for each role) methods (implementation provided in
       
  1171      * RelationSupport class).
       
  1172      * <P>It is also called in Relation Service setRole() (for given role) and
       
  1173      * setRoles() (for each role) methods.
       
  1174      * <P>To allow the Relation Service to maintain the consistency (in case
       
  1175      * of MBean unregistration) and to be able to perform queries, this method
       
  1176      * must be called when a role is updated.
       
  1177      *
       
  1178      * @param relationId  relation identifier of the updated relation
       
  1179      * @param newRole  new role (name and new value)
       
  1180      * @param oldValue  old role value (List of ObjectName objects)
       
  1181      *
       
  1182      * @exception IllegalArgumentException  if null parameter
       
  1183      * @exception RelationServiceNotRegisteredException  if the Relation
       
  1184      * Service is not registered in the MBean Server
       
  1185      * @exception RelationNotFoundException  if no relation for given id.
       
  1186      */
       
  1187     public void updateRoleMap(String relationId,
       
  1188                               Role newRole,
       
  1189                               List<ObjectName> oldValue)
       
  1190         throws IllegalArgumentException,
       
  1191                RelationServiceNotRegisteredException,
       
  1192                RelationNotFoundException {
       
  1193 
       
  1194         if (relationId == null ||
       
  1195             newRole == null ||
       
  1196             oldValue == null) {
       
  1197             String excMsg = "Invalid parameter.";
       
  1198             throw new IllegalArgumentException(excMsg);
       
  1199         }
       
  1200 
       
  1201         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
  1202                             relationId, newRole, oldValue);
       
  1203 
       
  1204         // Can throw RelationServiceNotRegisteredException
       
  1205         isActive();
       
  1206 
       
  1207         // Verifies the relation has been added in the Relation Service
       
  1208         // Can throw a RelationNotFoundException
       
  1209         Object result = getRelation(relationId);
       
  1210 
       
  1211         String roleName = newRole.getRoleName();
       
  1212         List<ObjectName> newRoleValue = newRole.getRoleValue();
       
  1213         // Note: no need to test if oldValue not null before cloning,
       
  1214         //       tested above.
       
  1215         List<ObjectName> oldRoleValue =
       
  1216             new ArrayList<ObjectName>(oldValue);
       
  1217 
       
  1218         // List of ObjectNames of new referenced MBeans
       
  1219         List<ObjectName> newRefList = new ArrayList<ObjectName>();
       
  1220 
       
  1221         for (ObjectName currObjName : newRoleValue) {
       
  1222 
       
  1223             // Checks if this ObjectName was already present in old value
       
  1224             // Note: use copy (oldRoleValue) instead of original
       
  1225             //       oldValue to speed up, as oldRoleValue is decreased
       
  1226             //       by removing unchanged references :)
       
  1227             int currObjNamePos = oldRoleValue.indexOf(currObjName);
       
  1228 
       
  1229             if (currObjNamePos == -1) {
       
  1230                 // New reference to an ObjectName
       
  1231 
       
  1232                 // Stores this reference into map
       
  1233                 // Returns true if new reference, false if MBean already
       
  1234                 // referenced
       
  1235                 boolean isNewFlag = addNewMBeanReference(currObjName,
       
  1236                                                         relationId,
       
  1237                                                         roleName);
       
  1238 
       
  1239                 if (isNewFlag) {
       
  1240                     // Adds it into list of new reference
       
  1241                     newRefList.add(currObjName);
       
  1242                 }
       
  1243 
       
  1244             } else {
       
  1245                 // MBean was already referenced in old value
       
  1246 
       
  1247                 // Removes it from old value (local list) to ignore it when
       
  1248                 // looking for remove MBean references
       
  1249                 oldRoleValue.remove(currObjNamePos);
       
  1250             }
       
  1251         }
       
  1252 
       
  1253         // List of ObjectNames of MBeans no longer referenced
       
  1254         List<ObjectName> obsRefList = new ArrayList<ObjectName>();
       
  1255 
       
  1256         // Each ObjectName remaining in oldRoleValue is an ObjectName no longer
       
  1257         // referenced in new value
       
  1258         for (ObjectName currObjName : oldRoleValue) {
       
  1259             // Removes MBean reference from map
       
  1260             // Returns true if the MBean is no longer referenced in any
       
  1261             // relation
       
  1262             boolean noLongerRefFlag = removeMBeanReference(currObjName,
       
  1263                                                           relationId,
       
  1264                                                           roleName,
       
  1265                                                           false);
       
  1266 
       
  1267             if (noLongerRefFlag) {
       
  1268                 // Adds it into list of references to be removed
       
  1269                 obsRefList.add(currObjName);
       
  1270             }
       
  1271         }
       
  1272 
       
  1273         // To avoid having one listener per ObjectName of referenced MBean,
       
  1274         // and to increase performances, there is only one listener recording
       
  1275         // all ObjectNames of interest
       
  1276         updateUnregistrationListener(newRefList, obsRefList);
       
  1277 
       
  1278         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1279         return;
       
  1280     }
       
  1281 
       
  1282     /**
       
  1283      * Removes given relation from the Relation Service.
       
  1284      * <P>A RelationNotification notification is sent, its type being:
       
  1285      * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation was
       
  1286      * only internal to the Relation Service
       
  1287      * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is
       
  1288      * registered as an MBean.
       
  1289      * <P>For MBeans referenced in such relation, nothing will be done,
       
  1290      *
       
  1291      * @param relationId  relation id of the relation to be removed
       
  1292      *
       
  1293      * @exception RelationServiceNotRegisteredException  if the Relation
       
  1294      * Service is not registered in the MBean Server
       
  1295      * @exception IllegalArgumentException  if null parameter
       
  1296      * @exception RelationNotFoundException  if no relation corresponding to
       
  1297      * given relation id
       
  1298      */
       
  1299     public void removeRelation(String relationId)
       
  1300         throws RelationServiceNotRegisteredException,
       
  1301                IllegalArgumentException,
       
  1302                RelationNotFoundException {
       
  1303 
       
  1304         // Can throw RelationServiceNotRegisteredException
       
  1305         isActive();
       
  1306 
       
  1307         if (relationId == null) {
       
  1308             String excMsg = "Invalid parameter.";
       
  1309             throw new IllegalArgumentException(excMsg);
       
  1310         }
       
  1311 
       
  1312         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
  1313 
       
  1314         // Checks there is a relation with this id
       
  1315         // Can throw RelationNotFoundException
       
  1316         Object result = getRelation(relationId);
       
  1317 
       
  1318         // Removes it from listener filter
       
  1319         if (result instanceof ObjectName) {
       
  1320             List<ObjectName> obsRefList = new ArrayList<ObjectName>();
       
  1321             obsRefList.add((ObjectName)result);
       
  1322             // Can throw a RelationServiceNotRegisteredException
       
  1323             updateUnregistrationListener(null, obsRefList);
       
  1324         }
       
  1325 
       
  1326         // Sends a notification
       
  1327         // Note: has to be done FIRST as needs the relation to be still in the
       
  1328         //       Relation Service
       
  1329         // No RelationNotFoundException as checked above
       
  1330 
       
  1331         // Revisit [cebro] Handle CIM "Delete" and "IfDeleted" qualifiers:
       
  1332         //   deleting the relation can mean to delete referenced MBeans. In
       
  1333         //   that case, MBeans to be unregistered are put in a list sent along
       
  1334         //   with the notification below
       
  1335 
       
  1336         // Can throw a RelationNotFoundException (but detected above)
       
  1337         sendRelationRemovalNotification(relationId, null);
       
  1338 
       
  1339         // Removes the relation from various internal maps
       
  1340 
       
  1341         //  - MBean reference map
       
  1342         // Retrieves the MBeans referenced in this relation
       
  1343         // Note: here we cannot use removeMBeanReference() because it would
       
  1344         //       require to know the MBeans referenced in the relation. For
       
  1345         //       that it would be necessary to call 'getReferencedMBeans()'
       
  1346         //       on the relation itself. Ok if it is an internal one, but if
       
  1347         //       it is an MBean, it is possible it is already unregistered, so
       
  1348         //       not available through the MBean Server.
       
  1349         List<ObjectName> refMBeanList = new ArrayList<ObjectName>();
       
  1350         // List of MBeans no longer referenced in any relation, to be
       
  1351         // removed fom the map
       
  1352         List<ObjectName> nonRefObjNameList = new ArrayList<ObjectName>();
       
  1353 
       
  1354         synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  1355 
       
  1356             for (ObjectName currRefObjName :
       
  1357                      myRefedMBeanObjName2RelIdsMap.keySet()) {
       
  1358 
       
  1359                 // Retrieves relations where the MBean is referenced
       
  1360                 Map<String,List<String>> relIdMap =
       
  1361                     myRefedMBeanObjName2RelIdsMap.get(currRefObjName);
       
  1362 
       
  1363                 if (relIdMap.containsKey(relationId)) {
       
  1364                     relIdMap.remove(relationId);
       
  1365                     refMBeanList.add(currRefObjName);
       
  1366                 }
       
  1367 
       
  1368                 if (relIdMap.isEmpty()) {
       
  1369                     // MBean no longer referenced
       
  1370                     // Note: do not remove it here because pointed by the
       
  1371                     //       iterator!
       
  1372                     nonRefObjNameList.add(currRefObjName);
       
  1373                 }
       
  1374             }
       
  1375 
       
  1376             // Cleans MBean reference map by removing MBeans no longer
       
  1377             // referenced
       
  1378             for (ObjectName currRefObjName : nonRefObjNameList) {
       
  1379                 myRefedMBeanObjName2RelIdsMap.remove(currRefObjName);
       
  1380             }
       
  1381         }
       
  1382 
       
  1383         // - Relation id to object map
       
  1384         synchronized(myRelId2ObjMap) {
       
  1385             myRelId2ObjMap.remove(relationId);
       
  1386         }
       
  1387 
       
  1388         if (result instanceof ObjectName) {
       
  1389             // - ObjectName to relation id map
       
  1390             synchronized(myRelMBeanObjName2RelIdMap) {
       
  1391                 myRelMBeanObjName2RelIdMap.remove((ObjectName)result);
       
  1392             }
       
  1393         }
       
  1394 
       
  1395         // Relation id to relation type name map
       
  1396         // First retrieves the relation type name
       
  1397         String relTypeName;
       
  1398         synchronized(myRelId2RelTypeMap) {
       
  1399             relTypeName = myRelId2RelTypeMap.get(relationId);
       
  1400             myRelId2RelTypeMap.remove(relationId);
       
  1401         }
       
  1402         // - Relation type name to relation id map
       
  1403         synchronized(myRelType2RelIdsMap) {
       
  1404             List<String> relIdList = myRelType2RelIdsMap.get(relTypeName);
       
  1405             if (relIdList != null) {
       
  1406                 // Can be null if called from removeRelationType()
       
  1407                 relIdList.remove(relationId);
       
  1408                 if (relIdList.isEmpty()) {
       
  1409                     // No other relation of that type
       
  1410                     myRelType2RelIdsMap.remove(relTypeName);
       
  1411                 }
       
  1412             }
       
  1413         }
       
  1414 
       
  1415         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1416         return;
       
  1417     }
       
  1418 
       
  1419     /**
       
  1420      * Purges the relations.
       
  1421      *
       
  1422      * <P>Depending on the purgeFlag value, this method is either called
       
  1423      * automatically when a notification is received for the unregistration of
       
  1424      * an MBean referenced in a relation (if the flag is set to true), or not
       
  1425      * (if the flag is set to false).
       
  1426      * <P>In that case it is up to the user to call it to maintain the
       
  1427      * consistency of the relations. To be kept in mind that if an MBean is
       
  1428      * unregistered and the purge not done immediately, if the ObjectName is
       
  1429      * reused and assigned to another MBean referenced in a relation, calling
       
  1430      * manually this purgeRelations() method will cause trouble, as will
       
  1431      * consider the ObjectName as corresponding to the unregistered MBean, not
       
  1432      * seeing the new one.
       
  1433      *
       
  1434      * <P>The behavior depends on the cardinality of the role where the
       
  1435      * unregistered MBean is referenced:
       
  1436      * <P>- if removing one MBean reference in the role makes its number of
       
  1437      * references less than the minimum degree, the relation has to be removed.
       
  1438      * <P>- if the remaining number of references after removing the MBean
       
  1439      * reference is still in the cardinality range, keep the relation and
       
  1440      * update it calling its handleMBeanUnregistration() callback.
       
  1441      *
       
  1442      * @exception RelationServiceNotRegisteredException  if the Relation
       
  1443      * Service is not registered in the MBean Server.
       
  1444      */
       
  1445     public void purgeRelations()
       
  1446         throws RelationServiceNotRegisteredException {
       
  1447 
       
  1448         RELATION_LOGGER.log(Level.TRACE, "ENTRY");
       
  1449 
       
  1450         // Can throw RelationServiceNotRegisteredException
       
  1451         isActive();
       
  1452 
       
  1453         // Revisit [cebro] Handle the CIM "Delete" and "IfDeleted" qualifier:
       
  1454         //    if the unregistered MBean has the "IfDeleted" qualifier,
       
  1455         //    possible that the relation itself or other referenced MBeans
       
  1456         //    have to be removed (then a notification would have to be sent
       
  1457         //    to inform that they should be unregistered.
       
  1458 
       
  1459 
       
  1460         // Clones the list of notifications to be able to still receive new
       
  1461         // notifications while proceeding those ones
       
  1462         List<MBeanServerNotification> localUnregNtfList;
       
  1463         synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  1464             localUnregNtfList =
       
  1465                 new ArrayList<MBeanServerNotification>(myUnregNtfList);
       
  1466             // Resets list
       
  1467             myUnregNtfList = new ArrayList<MBeanServerNotification>();
       
  1468         }
       
  1469 
       
  1470 
       
  1471         // Updates the listener filter to avoid receiving notifications for
       
  1472         // those MBeans again
       
  1473         // Makes also a local "myRefedMBeanObjName2RelIdsMap" map, mapping
       
  1474         // ObjectName -> relId -> roles, to remove the MBean from the global
       
  1475         // map
       
  1476         // List of references to be removed from the listener filter
       
  1477         List<ObjectName> obsRefList = new ArrayList<ObjectName>();
       
  1478         // Map including ObjectNames for unregistered MBeans, with
       
  1479         // referencing relation ids and roles
       
  1480         Map<ObjectName,Map<String,List<String>>> localMBean2RelIdMap =
       
  1481             new HashMap<ObjectName,Map<String,List<String>>>();
       
  1482 
       
  1483         synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  1484             for (MBeanServerNotification currNtf : localUnregNtfList) {
       
  1485 
       
  1486                 ObjectName unregMBeanName = currNtf.getMBeanName();
       
  1487 
       
  1488                 // Adds the unregsitered MBean in the list of references to
       
  1489                 // remove from the listener filter
       
  1490                 obsRefList.add(unregMBeanName);
       
  1491 
       
  1492                 // Retrieves the associated map of relation ids and roles
       
  1493                 Map<String,List<String>> relIdMap =
       
  1494                     myRefedMBeanObjName2RelIdsMap.get(unregMBeanName);
       
  1495                 localMBean2RelIdMap.put(unregMBeanName, relIdMap);
       
  1496 
       
  1497                 myRefedMBeanObjName2RelIdsMap.remove(unregMBeanName);
       
  1498             }
       
  1499         }
       
  1500 
       
  1501         // Updates the listener
       
  1502         // Can throw RelationServiceNotRegisteredException
       
  1503         updateUnregistrationListener(null, obsRefList);
       
  1504 
       
  1505         for (MBeanServerNotification currNtf : localUnregNtfList) {
       
  1506 
       
  1507             ObjectName unregMBeanName = currNtf.getMBeanName();
       
  1508 
       
  1509             // Retrieves the relations where the MBean is referenced
       
  1510             Map<String,List<String>> localRelIdMap =
       
  1511                     localMBean2RelIdMap.get(unregMBeanName);
       
  1512 
       
  1513             // List of relation ids where the unregistered MBean is
       
  1514             // referenced
       
  1515             for (Map.Entry<String,List<String>> currRel :
       
  1516                         localRelIdMap.entrySet()) {
       
  1517                 final String currRelId = currRel.getKey();
       
  1518                 // List of roles of the relation where the MBean is
       
  1519                 // referenced
       
  1520                 List<String> localRoleNameList = currRel.getValue();
       
  1521 
       
  1522                 // Checks if the relation has to be removed or not,
       
  1523                 // regarding expected minimum role cardinality and current
       
  1524                 // number of references after removal of the current one
       
  1525                 // If the relation is kept, calls
       
  1526                 // handleMBeanUnregistration() callback of the relation to
       
  1527                 // update it
       
  1528                 //
       
  1529                 // Can throw RelationServiceNotRegisteredException
       
  1530                 //
       
  1531                 // Shall not throw RelationNotFoundException,
       
  1532                 // RoleNotFoundException, MBeanException
       
  1533                 try {
       
  1534                     handleReferenceUnregistration(currRelId,
       
  1535                                                   unregMBeanName,
       
  1536                                                   localRoleNameList);
       
  1537                 } catch (RelationNotFoundException exc1) {
       
  1538                     throw new RuntimeException(exc1.getMessage());
       
  1539                 } catch (RoleNotFoundException exc2) {
       
  1540                     throw new RuntimeException(exc2.getMessage());
       
  1541                 }
       
  1542             }
       
  1543         }
       
  1544 
       
  1545         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1546         return;
       
  1547     }
       
  1548 
       
  1549     /**
       
  1550      * Retrieves the relations where a given MBean is referenced.
       
  1551      * <P>This corresponds to the CIM "References" and "ReferenceNames"
       
  1552      * operations.
       
  1553      *
       
  1554      * @param mbeanName  ObjectName of MBean
       
  1555      * @param relationTypeName  can be null; if specified, only the relations
       
  1556      * of that type will be considered in the search. Else all relation types
       
  1557      * are considered.
       
  1558      * @param roleName  can be null; if specified, only the relations
       
  1559      * where the MBean is referenced in that role will be returned. Else all
       
  1560      * roles are considered.
       
  1561      *
       
  1562      * @return an HashMap, where the keys are the relation ids of the relations
       
  1563      * where the MBean is referenced, and the value is, for each key,
       
  1564      * an ArrayList of role names (as an MBean can be referenced in several
       
  1565      * roles in the same relation).
       
  1566      *
       
  1567      * @exception IllegalArgumentException  if null parameter
       
  1568      */
       
  1569     public Map<String,List<String>>
       
  1570         findReferencingRelations(ObjectName mbeanName,
       
  1571                                  String relationTypeName,
       
  1572                                  String roleName)
       
  1573             throws IllegalArgumentException {
       
  1574 
       
  1575         if (mbeanName == null) {
       
  1576             String excMsg = "Invalid parameter.";
       
  1577             throw new IllegalArgumentException(excMsg);
       
  1578         }
       
  1579 
       
  1580         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
  1581                             mbeanName, relationTypeName, roleName);
       
  1582 
       
  1583         Map<String,List<String>> result = new HashMap<String,List<String>>();
       
  1584 
       
  1585         synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  1586 
       
  1587             // Retrieves the relations referencing the MBean
       
  1588             Map<String,List<String>> relId2RoleNamesMap =
       
  1589                 myRefedMBeanObjName2RelIdsMap.get(mbeanName);
       
  1590 
       
  1591             if (relId2RoleNamesMap != null) {
       
  1592 
       
  1593                 // Relation Ids where the MBean is referenced
       
  1594                 Set<String> allRelIdSet = relId2RoleNamesMap.keySet();
       
  1595 
       
  1596                 // List of relation ids of interest regarding the selected
       
  1597                 // relation type
       
  1598                 List<String> relIdList;
       
  1599                 if (relationTypeName == null) {
       
  1600                     // Considers all relations
       
  1601                     relIdList = new ArrayList<String>(allRelIdSet);
       
  1602 
       
  1603                 } else {
       
  1604 
       
  1605                     relIdList = new ArrayList<String>();
       
  1606 
       
  1607                     // Considers only the relation ids for relations of given
       
  1608                     // type
       
  1609                     for (String currRelId : allRelIdSet) {
       
  1610 
       
  1611                         // Retrieves its relation type
       
  1612                         String currRelTypeName;
       
  1613                         synchronized(myRelId2RelTypeMap) {
       
  1614                             currRelTypeName =
       
  1615                                 myRelId2RelTypeMap.get(currRelId);
       
  1616                         }
       
  1617 
       
  1618                         if (currRelTypeName.equals(relationTypeName)) {
       
  1619 
       
  1620                             relIdList.add(currRelId);
       
  1621 
       
  1622                         }
       
  1623                     }
       
  1624                 }
       
  1625 
       
  1626                 // Now looks at the roles where the MBean is expected to be
       
  1627                 // referenced
       
  1628 
       
  1629                 for (String currRelId : relIdList) {
       
  1630                     // Retrieves list of role names where the MBean is
       
  1631                     // referenced
       
  1632                     List<String> currRoleNameList =
       
  1633                         relId2RoleNamesMap.get(currRelId);
       
  1634 
       
  1635                     if (roleName == null) {
       
  1636                         // All roles to be considered
       
  1637                         // Note: no need to test if list not null before
       
  1638                         //       cloning, MUST be not null else bug :(
       
  1639                         result.put(currRelId,
       
  1640                                    new ArrayList<String>(currRoleNameList));
       
  1641 
       
  1642                     }  else if (currRoleNameList.contains(roleName)) {
       
  1643                         // Filters only the relations where the MBean is
       
  1644                         // referenced in // given role
       
  1645                         List<String> dummyList = new ArrayList<String>();
       
  1646                         dummyList.add(roleName);
       
  1647                         result.put(currRelId, dummyList);
       
  1648                     }
       
  1649                 }
       
  1650             }
       
  1651         }
       
  1652 
       
  1653         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1654         return result;
       
  1655     }
       
  1656 
       
  1657     /**
       
  1658      * Retrieves the MBeans associated to given one in a relation.
       
  1659      * <P>This corresponds to CIM Associators and AssociatorNames operations.
       
  1660      *
       
  1661      * @param mbeanName  ObjectName of MBean
       
  1662      * @param relationTypeName  can be null; if specified, only the relations
       
  1663      * of that type will be considered in the search. Else all
       
  1664      * relation types are considered.
       
  1665      * @param roleName  can be null; if specified, only the relations
       
  1666      * where the MBean is referenced in that role will be considered. Else all
       
  1667      * roles are considered.
       
  1668      *
       
  1669      * @return an HashMap, where the keys are the ObjectNames of the MBeans
       
  1670      * associated to given MBean, and the value is, for each key, an ArrayList
       
  1671      * of the relation ids of the relations where the key MBean is
       
  1672      * associated to given one (as they can be associated in several different
       
  1673      * relations).
       
  1674      *
       
  1675      * @exception IllegalArgumentException  if null parameter
       
  1676      */
       
  1677     public Map<ObjectName,List<String>>
       
  1678         findAssociatedMBeans(ObjectName mbeanName,
       
  1679                              String relationTypeName,
       
  1680                              String roleName)
       
  1681             throws IllegalArgumentException {
       
  1682 
       
  1683         if (mbeanName == null) {
       
  1684             String excMsg = "Invalid parameter.";
       
  1685             throw new IllegalArgumentException(excMsg);
       
  1686         }
       
  1687 
       
  1688         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
  1689                             mbeanName, relationTypeName, roleName);
       
  1690 
       
  1691         // Retrieves the map <relation id> -> <role names> for those
       
  1692         // criterias
       
  1693         Map<String,List<String>> relId2RoleNamesMap =
       
  1694             findReferencingRelations(mbeanName,
       
  1695                                      relationTypeName,
       
  1696                                      roleName);
       
  1697 
       
  1698         Map<ObjectName,List<String>> result =
       
  1699             new HashMap<ObjectName,List<String>>();
       
  1700 
       
  1701         for (String currRelId : relId2RoleNamesMap.keySet()) {
       
  1702 
       
  1703             // Retrieves ObjectNames of MBeans referenced in this relation
       
  1704             //
       
  1705             // Shall not throw a RelationNotFoundException if incorrect status
       
  1706             // of maps :(
       
  1707             Map<ObjectName,List<String>> objName2RoleNamesMap;
       
  1708             try {
       
  1709                 objName2RoleNamesMap = getReferencedMBeans(currRelId);
       
  1710             } catch (RelationNotFoundException exc) {
       
  1711                 throw new RuntimeException(exc.getMessage());
       
  1712             }
       
  1713 
       
  1714             // For each MBean associated to given one in a relation, adds the
       
  1715             // association <ObjectName> -> <relation id> into result map
       
  1716             for (ObjectName currObjName : objName2RoleNamesMap.keySet()) {
       
  1717 
       
  1718                 if (!(currObjName.equals(mbeanName))) {
       
  1719 
       
  1720                     // Sees if this MBean is already associated to the given
       
  1721                     // one in another relation
       
  1722                     List<String> currRelIdList = result.get(currObjName);
       
  1723                     if (currRelIdList == null) {
       
  1724 
       
  1725                         currRelIdList = new ArrayList<String>();
       
  1726                         currRelIdList.add(currRelId);
       
  1727                         result.put(currObjName, currRelIdList);
       
  1728 
       
  1729                     } else {
       
  1730                         currRelIdList.add(currRelId);
       
  1731                     }
       
  1732                 }
       
  1733             }
       
  1734         }
       
  1735 
       
  1736         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1737         return result;
       
  1738     }
       
  1739 
       
  1740     /**
       
  1741      * Returns the relation ids for relations of the given type.
       
  1742      *
       
  1743      * @param relationTypeName  relation type name
       
  1744      *
       
  1745      * @return an ArrayList of relation ids.
       
  1746      *
       
  1747      * @exception IllegalArgumentException  if null parameter
       
  1748      * @exception RelationTypeNotFoundException  if there is no relation type
       
  1749      * with that name.
       
  1750      */
       
  1751     public List<String> findRelationsOfType(String relationTypeName)
       
  1752         throws IllegalArgumentException,
       
  1753                RelationTypeNotFoundException {
       
  1754 
       
  1755         if (relationTypeName == null) {
       
  1756             String excMsg = "Invalid parameter.";
       
  1757             throw new IllegalArgumentException(excMsg);
       
  1758         }
       
  1759 
       
  1760         RELATION_LOGGER.log(Level.TRACE, "ENTRY");
       
  1761 
       
  1762         // Can throw RelationTypeNotFoundException
       
  1763         RelationType relType = getRelationType(relationTypeName);
       
  1764 
       
  1765         List<String> result;
       
  1766         synchronized(myRelType2RelIdsMap) {
       
  1767             List<String> result1 = myRelType2RelIdsMap.get(relationTypeName);
       
  1768             if (result1 == null)
       
  1769                 result = new ArrayList<String>();
       
  1770             else
       
  1771                 result = new ArrayList<String>(result1);
       
  1772         }
       
  1773 
       
  1774         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1775         return result;
       
  1776     }
       
  1777 
       
  1778     /**
       
  1779      * Retrieves role value for given role name in given relation.
       
  1780      *
       
  1781      * @param relationId  relation id
       
  1782      * @param roleName  name of role
       
  1783      *
       
  1784      * @return the ArrayList of ObjectName objects being the role value
       
  1785      *
       
  1786      * @exception RelationServiceNotRegisteredException  if the Relation
       
  1787      * Service is not registered
       
  1788      * @exception IllegalArgumentException  if null parameter
       
  1789      * @exception RelationNotFoundException  if no relation with given id
       
  1790      * @exception RoleNotFoundException  if:
       
  1791      * <P>- there is no role with given name
       
  1792      * <P>or
       
  1793      * <P>- the role is not readable.
       
  1794      *
       
  1795      * @see #setRole
       
  1796      */
       
  1797     public List<ObjectName> getRole(String relationId,
       
  1798                                     String roleName)
       
  1799         throws RelationServiceNotRegisteredException,
       
  1800                IllegalArgumentException,
       
  1801                RelationNotFoundException,
       
  1802                RoleNotFoundException {
       
  1803 
       
  1804         if (relationId == null || roleName == null) {
       
  1805             String excMsg = "Invalid parameter.";
       
  1806             throw new IllegalArgumentException(excMsg);
       
  1807         }
       
  1808 
       
  1809         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
  1810                             relationId, roleName);
       
  1811 
       
  1812         // Can throw RelationServiceNotRegisteredException
       
  1813         isActive();
       
  1814 
       
  1815         // Can throw a RelationNotFoundException
       
  1816         Object relObj = getRelation(relationId);
       
  1817 
       
  1818         List<ObjectName> result;
       
  1819 
       
  1820         if (relObj instanceof RelationSupport) {
       
  1821             // Internal relation
       
  1822             // Can throw RoleNotFoundException
       
  1823             result = cast(
       
  1824                 ((RelationSupport)relObj).getRoleInt(roleName,
       
  1825                                                      true,
       
  1826                                                      this,
       
  1827                                                      false));
       
  1828 
       
  1829         } else {
       
  1830             // Relation MBean
       
  1831             Object[] params = new Object[1];
       
  1832             params[0] = roleName;
       
  1833             String[] signature = new String[1];
       
  1834             signature[0] = "java.lang.String";
       
  1835             // Can throw MBeanException wrapping a RoleNotFoundException:
       
  1836             // throw wrapped exception
       
  1837             //
       
  1838             // Shall not throw InstanceNotFoundException or ReflectionException
       
  1839             try {
       
  1840                 List<ObjectName> invokeResult = cast(
       
  1841                     myMBeanServer.invoke(((ObjectName)relObj),
       
  1842                                          "getRole",
       
  1843                                          params,
       
  1844                                          signature));
       
  1845                 if (invokeResult == null || invokeResult instanceof ArrayList<?>)
       
  1846                     result = invokeResult;
       
  1847                 else
       
  1848                     result = new ArrayList<ObjectName>(invokeResult);
       
  1849             } catch (InstanceNotFoundException exc1) {
       
  1850                 throw new RuntimeException(exc1.getMessage());
       
  1851             } catch (ReflectionException exc2) {
       
  1852                 throw new RuntimeException(exc2.getMessage());
       
  1853             } catch (MBeanException exc3) {
       
  1854                 Exception wrappedExc = exc3.getTargetException();
       
  1855                 if (wrappedExc instanceof RoleNotFoundException) {
       
  1856                     throw ((RoleNotFoundException)wrappedExc);
       
  1857                 } else {
       
  1858                     throw new RuntimeException(wrappedExc.getMessage());
       
  1859                 }
       
  1860             }
       
  1861         }
       
  1862 
       
  1863         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1864         return result;
       
  1865     }
       
  1866 
       
  1867     /**
       
  1868      * Retrieves values of roles with given names in given relation.
       
  1869      *
       
  1870      * @param relationId  relation id
       
  1871      * @param roleNameArray  array of names of roles to be retrieved
       
  1872      *
       
  1873      * @return a RoleResult object, including a RoleList (for roles
       
  1874      * successfully retrieved) and a RoleUnresolvedList (for roles not
       
  1875      * retrieved).
       
  1876      *
       
  1877      * @exception RelationServiceNotRegisteredException  if the Relation
       
  1878      * Service is not registered in the MBean Server
       
  1879      * @exception IllegalArgumentException  if null parameter
       
  1880      * @exception RelationNotFoundException  if no relation with given id
       
  1881      *
       
  1882      * @see #setRoles
       
  1883      */
       
  1884     public RoleResult getRoles(String relationId,
       
  1885                                String[] roleNameArray)
       
  1886         throws RelationServiceNotRegisteredException,
       
  1887                IllegalArgumentException,
       
  1888                RelationNotFoundException {
       
  1889 
       
  1890         if (relationId == null || roleNameArray == null) {
       
  1891             String excMsg = "Invalid parameter.";
       
  1892             throw new IllegalArgumentException(excMsg);
       
  1893         }
       
  1894 
       
  1895         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
  1896 
       
  1897         // Can throw RelationServiceNotRegisteredException
       
  1898         isActive();
       
  1899 
       
  1900         // Can throw a RelationNotFoundException
       
  1901         Object relObj = getRelation(relationId);
       
  1902 
       
  1903         RoleResult result;
       
  1904 
       
  1905         if (relObj instanceof RelationSupport) {
       
  1906             // Internal relation
       
  1907             result = ((RelationSupport)relObj).getRolesInt(roleNameArray,
       
  1908                                                         true,
       
  1909                                                         this);
       
  1910         } else {
       
  1911             // Relation MBean
       
  1912             Object[] params = new Object[1];
       
  1913             params[0] = roleNameArray;
       
  1914             String[] signature = new String[1];
       
  1915             try {
       
  1916                 signature[0] = (roleNameArray.getClass()).getName();
       
  1917             } catch (Exception exc) {
       
  1918                 // OK : This is an array of java.lang.String
       
  1919                 //      so this should never happen...
       
  1920             }
       
  1921             // Shall not throw InstanceNotFoundException, ReflectionException
       
  1922             // or MBeanException
       
  1923             try {
       
  1924                 result = (RoleResult)
       
  1925                     (myMBeanServer.invoke(((ObjectName)relObj),
       
  1926                                           "getRoles",
       
  1927                                           params,
       
  1928                                           signature));
       
  1929             } catch (InstanceNotFoundException exc1) {
       
  1930                 throw new RuntimeException(exc1.getMessage());
       
  1931             } catch (ReflectionException exc2) {
       
  1932                 throw new RuntimeException(exc2.getMessage());
       
  1933             } catch (MBeanException exc3) {
       
  1934                 throw new
       
  1935                     RuntimeException((exc3.getTargetException()).getMessage());
       
  1936             }
       
  1937         }
       
  1938 
       
  1939         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1940         return result;
       
  1941     }
       
  1942 
       
  1943     /**
       
  1944      * Returns all roles present in the relation.
       
  1945      *
       
  1946      * @param relationId  relation id
       
  1947      *
       
  1948      * @return a RoleResult object, including a RoleList (for roles
       
  1949      * successfully retrieved) and a RoleUnresolvedList (for roles not
       
  1950      * readable).
       
  1951      *
       
  1952      * @exception IllegalArgumentException  if null parameter
       
  1953      * @exception RelationNotFoundException  if no relation for given id
       
  1954      * @exception RelationServiceNotRegisteredException  if the Relation
       
  1955      * Service is not registered in the MBean Server
       
  1956      */
       
  1957     public RoleResult getAllRoles(String relationId)
       
  1958         throws IllegalArgumentException,
       
  1959                RelationNotFoundException,
       
  1960                RelationServiceNotRegisteredException {
       
  1961 
       
  1962         if (relationId == null) {
       
  1963             String excMsg = "Invalid parameter.";
       
  1964             throw new IllegalArgumentException(excMsg);
       
  1965         }
       
  1966 
       
  1967         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
  1968 
       
  1969         // Can throw a RelationNotFoundException
       
  1970         Object relObj = getRelation(relationId);
       
  1971 
       
  1972         RoleResult result;
       
  1973 
       
  1974         if (relObj instanceof RelationSupport) {
       
  1975             // Internal relation
       
  1976             result = ((RelationSupport)relObj).getAllRolesInt(true, this);
       
  1977 
       
  1978         } else {
       
  1979             // Relation MBean
       
  1980             // Shall not throw any Exception
       
  1981             try {
       
  1982                 result = (RoleResult)
       
  1983                     (myMBeanServer.getAttribute(((ObjectName)relObj),
       
  1984                                                 "AllRoles"));
       
  1985             } catch (Exception exc) {
       
  1986                 throw new RuntimeException(exc.getMessage());
       
  1987             }
       
  1988         }
       
  1989 
       
  1990         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  1991         return result;
       
  1992     }
       
  1993 
       
  1994     /**
       
  1995      * Retrieves the number of MBeans currently referenced in the given role.
       
  1996      *
       
  1997      * @param relationId  relation id
       
  1998      * @param roleName  name of role
       
  1999      *
       
  2000      * @return the number of currently referenced MBeans in that role
       
  2001      *
       
  2002      * @exception IllegalArgumentException  if null parameter
       
  2003      * @exception RelationNotFoundException  if no relation with given id
       
  2004      * @exception RoleNotFoundException  if there is no role with given name
       
  2005      */
       
  2006     public Integer getRoleCardinality(String relationId,
       
  2007                                       String roleName)
       
  2008         throws IllegalArgumentException,
       
  2009                RelationNotFoundException,
       
  2010                RoleNotFoundException {
       
  2011 
       
  2012         if (relationId == null || roleName == null) {
       
  2013             String excMsg = "Invalid parameter.";
       
  2014             throw new IllegalArgumentException(excMsg);
       
  2015         }
       
  2016 
       
  2017         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
  2018                             relationId, roleName);
       
  2019 
       
  2020         // Can throw a RelationNotFoundException
       
  2021         Object relObj = getRelation(relationId);
       
  2022 
       
  2023         Integer result;
       
  2024 
       
  2025         if (relObj instanceof RelationSupport) {
       
  2026             // Internal relation
       
  2027             // Can throw RoleNotFoundException
       
  2028             result = ((RelationSupport)relObj).getRoleCardinality(roleName);
       
  2029 
       
  2030         } else {
       
  2031             // Relation MBean
       
  2032             Object[] params = new Object[1];
       
  2033             params[0] = roleName;
       
  2034             String[] signature = new String[1];
       
  2035             signature[0] = "java.lang.String";
       
  2036             // Can throw MBeanException wrapping RoleNotFoundException:
       
  2037             // throw wrapped exception
       
  2038             //
       
  2039             // Shall not throw InstanceNotFoundException or ReflectionException
       
  2040             try {
       
  2041                 result = (Integer)
       
  2042                     (myMBeanServer.invoke(((ObjectName)relObj),
       
  2043                                           "getRoleCardinality",
       
  2044                                           params,
       
  2045                                           signature));
       
  2046             } catch (InstanceNotFoundException exc1) {
       
  2047                 throw new RuntimeException(exc1.getMessage());
       
  2048             } catch (ReflectionException exc2) {
       
  2049                 throw new RuntimeException(exc2.getMessage());
       
  2050             } catch (MBeanException exc3) {
       
  2051                 Exception wrappedExc = exc3.getTargetException();
       
  2052                 if (wrappedExc instanceof RoleNotFoundException) {
       
  2053                     throw ((RoleNotFoundException)wrappedExc);
       
  2054                 } else {
       
  2055                     throw new RuntimeException(wrappedExc.getMessage());
       
  2056                 }
       
  2057             }
       
  2058         }
       
  2059 
       
  2060         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2061         return result;
       
  2062     }
       
  2063 
       
  2064     /**
       
  2065      * Sets the given role in given relation.
       
  2066      * <P>Will check the role according to its corresponding role definition
       
  2067      * provided in relation's relation type
       
  2068      * <P>The Relation Service will keep track of the change to keep the
       
  2069      * consistency of relations by handling referenced MBean deregistrations.
       
  2070      *
       
  2071      * @param relationId  relation id
       
  2072      * @param role  role to be set (name and new value)
       
  2073      *
       
  2074      * @exception RelationServiceNotRegisteredException  if the Relation
       
  2075      * Service is not registered in the MBean Server
       
  2076      * @exception IllegalArgumentException  if null parameter
       
  2077      * @exception RelationNotFoundException  if no relation with given id
       
  2078      * @exception RoleNotFoundException  if the role does not exist or is not
       
  2079      * writable
       
  2080      * @exception InvalidRoleValueException  if value provided for role is not
       
  2081      * valid:
       
  2082      * <P>- the number of referenced MBeans in given value is less than
       
  2083      * expected minimum degree
       
  2084      * <P>or
       
  2085      * <P>- the number of referenced MBeans in provided value exceeds expected
       
  2086      * maximum degree
       
  2087      * <P>or
       
  2088      * <P>- one referenced MBean in the value is not an Object of the MBean
       
  2089      * class expected for that role
       
  2090      * <P>or
       
  2091      * <P>- an MBean provided for that role does not exist
       
  2092      *
       
  2093      * @see #getRole
       
  2094      */
       
  2095     public void setRole(String relationId,
       
  2096                         Role role)
       
  2097         throws RelationServiceNotRegisteredException,
       
  2098                IllegalArgumentException,
       
  2099                RelationNotFoundException,
       
  2100                RoleNotFoundException,
       
  2101                InvalidRoleValueException {
       
  2102 
       
  2103         if (relationId == null || role == null) {
       
  2104             String excMsg = "Invalid parameter.";
       
  2105             throw new IllegalArgumentException(excMsg);
       
  2106         }
       
  2107 
       
  2108         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
  2109                             relationId, role);
       
  2110 
       
  2111         // Can throw RelationServiceNotRegisteredException
       
  2112         isActive();
       
  2113 
       
  2114         // Can throw a RelationNotFoundException
       
  2115         Object relObj = getRelation(relationId);
       
  2116 
       
  2117         if (relObj instanceof RelationSupport) {
       
  2118             // Internal relation
       
  2119             // Can throw RoleNotFoundException,
       
  2120             // InvalidRoleValueException and
       
  2121             // RelationServiceNotRegisteredException
       
  2122             //
       
  2123             // Shall not throw RelationTypeNotFoundException
       
  2124             // (as relation exists in the RS, its relation type is known)
       
  2125             try {
       
  2126                 ((RelationSupport)relObj).setRoleInt(role,
       
  2127                                                   true,
       
  2128                                                   this,
       
  2129                                                   false);
       
  2130 
       
  2131             } catch (RelationTypeNotFoundException exc) {
       
  2132                 throw new RuntimeException(exc.getMessage());
       
  2133             }
       
  2134 
       
  2135         } else {
       
  2136             // Relation MBean
       
  2137             Object[] params = new Object[1];
       
  2138             params[0] = role;
       
  2139             String[] signature = new String[1];
       
  2140             signature[0] = "javax.management.relation.Role";
       
  2141             // Can throw MBeanException wrapping RoleNotFoundException,
       
  2142             // InvalidRoleValueException
       
  2143             //
       
  2144             // Shall not MBeanException wrapping an MBeanException wrapping
       
  2145             // RelationTypeNotFoundException, or ReflectionException, or
       
  2146             // InstanceNotFoundException
       
  2147             try {
       
  2148                 myMBeanServer.setAttribute(((ObjectName)relObj),
       
  2149                                            new Attribute("Role", role));
       
  2150 
       
  2151             } catch (InstanceNotFoundException exc1) {
       
  2152                 throw new RuntimeException(exc1.getMessage());
       
  2153             } catch (ReflectionException exc3) {
       
  2154                 throw new RuntimeException(exc3.getMessage());
       
  2155             } catch (MBeanException exc2) {
       
  2156                 Exception wrappedExc = exc2.getTargetException();
       
  2157                 if (wrappedExc instanceof RoleNotFoundException) {
       
  2158                     throw ((RoleNotFoundException)wrappedExc);
       
  2159                 } else if (wrappedExc instanceof InvalidRoleValueException) {
       
  2160                     throw ((InvalidRoleValueException)wrappedExc);
       
  2161                 } else {
       
  2162                     throw new RuntimeException(wrappedExc.getMessage());
       
  2163 
       
  2164                 }
       
  2165             } catch (AttributeNotFoundException exc4) {
       
  2166               throw new RuntimeException(exc4.getMessage());
       
  2167             } catch (InvalidAttributeValueException exc5) {
       
  2168               throw new RuntimeException(exc5.getMessage());
       
  2169             }
       
  2170         }
       
  2171 
       
  2172         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2173         return;
       
  2174     }
       
  2175 
       
  2176     /**
       
  2177      * Sets the given roles in given relation.
       
  2178      * <P>Will check the role according to its corresponding role definition
       
  2179      * provided in relation's relation type
       
  2180      * <P>The Relation Service keeps track of the changes to keep the
       
  2181      * consistency of relations by handling referenced MBean deregistrations.
       
  2182      *
       
  2183      * @param relationId  relation id
       
  2184      * @param roleList  list of roles to be set
       
  2185      *
       
  2186      * @return a RoleResult object, including a RoleList (for roles
       
  2187      * successfully set) and a RoleUnresolvedList (for roles not
       
  2188      * set).
       
  2189      *
       
  2190      * @exception RelationServiceNotRegisteredException  if the Relation
       
  2191      * Service is not registered in the MBean Server
       
  2192      * @exception IllegalArgumentException  if null parameter
       
  2193      * @exception RelationNotFoundException  if no relation with given id
       
  2194      *
       
  2195      * @see #getRoles
       
  2196      */
       
  2197     public RoleResult setRoles(String relationId,
       
  2198                                RoleList roleList)
       
  2199         throws RelationServiceNotRegisteredException,
       
  2200                IllegalArgumentException,
       
  2201                RelationNotFoundException {
       
  2202 
       
  2203         if (relationId == null || roleList == null) {
       
  2204             String excMsg = "Invalid parameter.";
       
  2205             throw new IllegalArgumentException(excMsg);
       
  2206         }
       
  2207 
       
  2208         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
  2209                             relationId, roleList);
       
  2210 
       
  2211         // Can throw RelationServiceNotRegisteredException
       
  2212         isActive();
       
  2213 
       
  2214         // Can throw a RelationNotFoundException
       
  2215         Object relObj = getRelation(relationId);
       
  2216 
       
  2217         RoleResult result;
       
  2218 
       
  2219         if (relObj instanceof RelationSupport) {
       
  2220             // Internal relation
       
  2221             // Can throw RelationServiceNotRegisteredException
       
  2222             //
       
  2223             // Shall not throw RelationTypeNotFoundException (as relation is
       
  2224             // known, its relation type exists)
       
  2225             try {
       
  2226                 result = ((RelationSupport)relObj).setRolesInt(roleList,
       
  2227                                                             true,
       
  2228                                                             this);
       
  2229             } catch (RelationTypeNotFoundException exc) {
       
  2230                 throw new RuntimeException(exc.getMessage());
       
  2231             }
       
  2232 
       
  2233         } else {
       
  2234             // Relation MBean
       
  2235             Object[] params = new Object[1];
       
  2236             params[0] = roleList;
       
  2237             String[] signature = new String[1];
       
  2238             signature[0] = "javax.management.relation.RoleList";
       
  2239             // Shall not throw InstanceNotFoundException or an MBeanException
       
  2240             // or ReflectionException
       
  2241             try {
       
  2242                 result = (RoleResult)
       
  2243                     (myMBeanServer.invoke(((ObjectName)relObj),
       
  2244                                           "setRoles",
       
  2245                                           params,
       
  2246                                           signature));
       
  2247             } catch (InstanceNotFoundException exc1) {
       
  2248                 throw new RuntimeException(exc1.getMessage());
       
  2249             } catch (ReflectionException exc3) {
       
  2250                 throw new RuntimeException(exc3.getMessage());
       
  2251             } catch (MBeanException exc2) {
       
  2252                 throw new
       
  2253                     RuntimeException((exc2.getTargetException()).getMessage());
       
  2254             }
       
  2255         }
       
  2256 
       
  2257         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2258         return result;
       
  2259     }
       
  2260 
       
  2261     /**
       
  2262      * Retrieves MBeans referenced in the various roles of the relation.
       
  2263      *
       
  2264      * @param relationId  relation id
       
  2265      *
       
  2266      * @return a HashMap mapping:
       
  2267      * <P> ObjectName {@literal ->} ArrayList of String (role names)
       
  2268      *
       
  2269      * @exception IllegalArgumentException  if null parameter
       
  2270      * @exception RelationNotFoundException  if no relation for given
       
  2271      * relation id
       
  2272      */
       
  2273     public Map<ObjectName,List<String>>
       
  2274         getReferencedMBeans(String relationId)
       
  2275             throws IllegalArgumentException,
       
  2276         RelationNotFoundException {
       
  2277 
       
  2278         if (relationId == null) {
       
  2279             String excMsg = "Invalid parameter.";
       
  2280             throw new IllegalArgumentException(excMsg);
       
  2281         }
       
  2282 
       
  2283         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}",
       
  2284                             relationId);
       
  2285 
       
  2286         // Can throw a RelationNotFoundException
       
  2287         Object relObj = getRelation(relationId);
       
  2288 
       
  2289         Map<ObjectName,List<String>> result;
       
  2290 
       
  2291         if (relObj instanceof RelationSupport) {
       
  2292             // Internal relation
       
  2293             result = ((RelationSupport)relObj).getReferencedMBeans();
       
  2294 
       
  2295         } else {
       
  2296             // Relation MBean
       
  2297             // No Exception
       
  2298             try {
       
  2299                 result = cast(
       
  2300                     myMBeanServer.getAttribute(((ObjectName)relObj),
       
  2301                                                "ReferencedMBeans"));
       
  2302             } catch (Exception exc) {
       
  2303                 throw new RuntimeException(exc.getMessage());
       
  2304             }
       
  2305         }
       
  2306 
       
  2307         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2308         return result;
       
  2309     }
       
  2310 
       
  2311     /**
       
  2312      * Returns name of associated relation type for given relation.
       
  2313      *
       
  2314      * @param relationId  relation id
       
  2315      *
       
  2316      * @return the name of the associated relation type.
       
  2317      *
       
  2318      * @exception IllegalArgumentException  if null parameter
       
  2319      * @exception RelationNotFoundException  if no relation for given
       
  2320      * relation id
       
  2321      */
       
  2322     public String getRelationTypeName(String relationId)
       
  2323         throws IllegalArgumentException,
       
  2324                RelationNotFoundException {
       
  2325 
       
  2326         if (relationId == null) {
       
  2327             String excMsg = "Invalid parameter.";
       
  2328             throw new IllegalArgumentException(excMsg);
       
  2329         }
       
  2330 
       
  2331         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
  2332 
       
  2333         // Can throw a RelationNotFoundException
       
  2334         Object relObj = getRelation(relationId);
       
  2335 
       
  2336         String result;
       
  2337 
       
  2338         if (relObj instanceof RelationSupport) {
       
  2339             // Internal relation
       
  2340             result = ((RelationSupport)relObj).getRelationTypeName();
       
  2341 
       
  2342         } else {
       
  2343             // Relation MBean
       
  2344             // No Exception
       
  2345             try {
       
  2346                 result = (String)
       
  2347                     (myMBeanServer.getAttribute(((ObjectName)relObj),
       
  2348                                                 "RelationTypeName"));
       
  2349             } catch (Exception exc) {
       
  2350                 throw new RuntimeException(exc.getMessage());
       
  2351             }
       
  2352         }
       
  2353 
       
  2354         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2355         return result;
       
  2356     }
       
  2357 
       
  2358     //
       
  2359     // NotificationListener Interface
       
  2360     //
       
  2361 
       
  2362     /**
       
  2363      * Invoked when a JMX notification occurs.
       
  2364      * Currently handles notifications for unregistration of MBeans, either
       
  2365      * referenced in a relation role or being a relation itself.
       
  2366      *
       
  2367      * @param notif  The notification.
       
  2368      * @param handback  An opaque object which helps the listener to
       
  2369      * associate information regarding the MBean emitter (can be null).
       
  2370      */
       
  2371     public void handleNotification(Notification notif,
       
  2372                                    Object handback) {
       
  2373 
       
  2374         if (notif == null) {
       
  2375             String excMsg = "Invalid parameter.";
       
  2376             throw new IllegalArgumentException(excMsg);
       
  2377         }
       
  2378 
       
  2379         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", notif);
       
  2380 
       
  2381         if (notif instanceof MBeanServerNotification) {
       
  2382 
       
  2383             MBeanServerNotification mbsNtf = (MBeanServerNotification) notif;
       
  2384             String ntfType = notif.getType();
       
  2385 
       
  2386             if (ntfType.equals(
       
  2387                        MBeanServerNotification.UNREGISTRATION_NOTIFICATION )) {
       
  2388                 ObjectName mbeanName =
       
  2389                     ((MBeanServerNotification)notif).getMBeanName();
       
  2390 
       
  2391                 // Note: use a flag to block access to
       
  2392                 // myRefedMBeanObjName2RelIdsMap only for a quick access
       
  2393                 boolean isRefedMBeanFlag = false;
       
  2394                 synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  2395 
       
  2396                     if (myRefedMBeanObjName2RelIdsMap.containsKey(mbeanName)) {
       
  2397                         // Unregistration of a referenced MBean
       
  2398                         synchronized(myUnregNtfList) {
       
  2399                             myUnregNtfList.add(mbsNtf);
       
  2400                         }
       
  2401                         isRefedMBeanFlag = true;
       
  2402                     }
       
  2403                     if (isRefedMBeanFlag && myPurgeFlag) {
       
  2404                         // Immediate purge
       
  2405                         // Can throw RelationServiceNotRegisteredException
       
  2406                         // but assume that will be fine :)
       
  2407                         try {
       
  2408                             purgeRelations();
       
  2409                         } catch (Exception exc) {
       
  2410                             throw new RuntimeException(exc.getMessage());
       
  2411                         }
       
  2412                     }
       
  2413                 }
       
  2414 
       
  2415                 // Note: do both tests as a relation can be an MBean and be
       
  2416                 //       itself referenced in another relation :)
       
  2417                 String relId;
       
  2418                 synchronized(myRelMBeanObjName2RelIdMap){
       
  2419                     relId = myRelMBeanObjName2RelIdMap.get(mbeanName);
       
  2420                 }
       
  2421                 if (relId != null) {
       
  2422                     // Unregistration of a relation MBean
       
  2423                     // Can throw RelationTypeNotFoundException,
       
  2424                     // RelationServiceNotRegisteredException
       
  2425                     //
       
  2426                     // Shall not throw RelationTypeNotFoundException or
       
  2427                     // InstanceNotFoundException
       
  2428                     try {
       
  2429                         removeRelation(relId);
       
  2430                     } catch (Exception exc) {
       
  2431                         throw new RuntimeException(exc.getMessage());
       
  2432                     }
       
  2433                 }
       
  2434             }
       
  2435         }
       
  2436 
       
  2437         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2438         return;
       
  2439     }
       
  2440 
       
  2441     //
       
  2442     // NotificationBroadcaster interface
       
  2443     //
       
  2444 
       
  2445     /**
       
  2446      * Returns a NotificationInfo object containing the name of the Java class
       
  2447      * of the notification and the notification types sent.
       
  2448      */
       
  2449     public MBeanNotificationInfo[] getNotificationInfo() {
       
  2450 
       
  2451         RELATION_LOGGER.log(Level.TRACE, "ENTRY");
       
  2452 
       
  2453         String ntfClass = "javax.management.relation.RelationNotification";
       
  2454 
       
  2455         String[] ntfTypes = new String[] {
       
  2456             RelationNotification.RELATION_BASIC_CREATION,
       
  2457             RelationNotification.RELATION_MBEAN_CREATION,
       
  2458             RelationNotification.RELATION_BASIC_UPDATE,
       
  2459             RelationNotification.RELATION_MBEAN_UPDATE,
       
  2460             RelationNotification.RELATION_BASIC_REMOVAL,
       
  2461             RelationNotification.RELATION_MBEAN_REMOVAL,
       
  2462         };
       
  2463 
       
  2464         String ntfDesc = "Sent when a relation is created, updated or deleted.";
       
  2465 
       
  2466         MBeanNotificationInfo ntfInfo =
       
  2467             new MBeanNotificationInfo(ntfTypes, ntfClass, ntfDesc);
       
  2468 
       
  2469         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2470         return new MBeanNotificationInfo[] {ntfInfo};
       
  2471     }
       
  2472 
       
  2473     //
       
  2474     // Misc
       
  2475     //
       
  2476 
       
  2477     // Adds given object as a relation type.
       
  2478     //
       
  2479     // -param relationTypeObj  relation type object
       
  2480     //
       
  2481     // -exception IllegalArgumentException  if null parameter
       
  2482     // -exception InvalidRelationTypeException  if there is already a relation
       
  2483     //  type with that name
       
  2484     private void addRelationTypeInt(RelationType relationTypeObj)
       
  2485         throws IllegalArgumentException,
       
  2486                InvalidRelationTypeException {
       
  2487 
       
  2488         if (relationTypeObj == null) {
       
  2489             String excMsg = "Invalid parameter.";
       
  2490             throw new IllegalArgumentException(excMsg);
       
  2491         }
       
  2492 
       
  2493         RELATION_LOGGER.log(Level.TRACE, "ENTRY");
       
  2494 
       
  2495         String relTypeName = relationTypeObj.getRelationTypeName();
       
  2496 
       
  2497         // Checks that there is not already a relation type with that name
       
  2498         // existing in the Relation Service
       
  2499         try {
       
  2500             // Can throw a RelationTypeNotFoundException (in fact should ;)
       
  2501             RelationType relType = getRelationType(relTypeName);
       
  2502 
       
  2503             if (relType != null) {
       
  2504                 String excMsg = "There is already a relation type in the Relation Service with name ";
       
  2505                 StringBuilder excMsgStrB = new StringBuilder(excMsg);
       
  2506                 excMsgStrB.append(relTypeName);
       
  2507                 throw new InvalidRelationTypeException(excMsgStrB.toString());
       
  2508             }
       
  2509 
       
  2510         } catch (RelationTypeNotFoundException exc) {
       
  2511             // OK : The RelationType could not be found.
       
  2512         }
       
  2513 
       
  2514         // Adds the relation type
       
  2515         synchronized(myRelType2ObjMap) {
       
  2516             myRelType2ObjMap.put(relTypeName, relationTypeObj);
       
  2517         }
       
  2518 
       
  2519         if (relationTypeObj instanceof RelationTypeSupport) {
       
  2520             ((RelationTypeSupport)relationTypeObj).setRelationServiceFlag(true);
       
  2521         }
       
  2522 
       
  2523         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2524         return;
       
  2525      }
       
  2526 
       
  2527     // Retrieves relation type with given name
       
  2528     //
       
  2529     // -param relationTypeName  expected name of a relation type created in the
       
  2530     //  Relation Service
       
  2531     //
       
  2532     // -return RelationType object corresponding to given name
       
  2533     //
       
  2534     // -exception IllegalArgumentException  if null parameter
       
  2535     // -exception RelationTypeNotFoundException  if no relation type for that
       
  2536     //  name created in Relation Service
       
  2537     //
       
  2538     RelationType getRelationType(String relationTypeName)
       
  2539         throws IllegalArgumentException,
       
  2540                RelationTypeNotFoundException {
       
  2541 
       
  2542         if (relationTypeName == null) {
       
  2543             String excMsg = "Invalid parameter.";
       
  2544             throw new IllegalArgumentException(excMsg);
       
  2545         }
       
  2546 
       
  2547         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationTypeName);
       
  2548 
       
  2549         // No null relation type accepted, so can use get()
       
  2550         RelationType relType;
       
  2551         synchronized(myRelType2ObjMap) {
       
  2552             relType = (myRelType2ObjMap.get(relationTypeName));
       
  2553         }
       
  2554 
       
  2555         if (relType == null) {
       
  2556             String excMsg = "No relation type created in the Relation Service with the name ";
       
  2557             StringBuilder excMsgStrB = new StringBuilder(excMsg);
       
  2558             excMsgStrB.append(relationTypeName);
       
  2559             throw new RelationTypeNotFoundException(excMsgStrB.toString());
       
  2560         }
       
  2561 
       
  2562         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2563         return relType;
       
  2564     }
       
  2565 
       
  2566     // Retrieves relation corresponding to given relation id.
       
  2567     // Returns either:
       
  2568     // - a RelationSupport object if the relation is internal
       
  2569     // or
       
  2570     // - the ObjectName of the corresponding MBean
       
  2571     //
       
  2572     // -param relationId  expected relation id
       
  2573     //
       
  2574     // -return RelationSupport object or ObjectName of relation with given id
       
  2575     //
       
  2576     // -exception IllegalArgumentException  if null parameter
       
  2577     // -exception RelationNotFoundException  if no relation for that
       
  2578     //  relation id created in Relation Service
       
  2579     //
       
  2580     Object getRelation(String relationId)
       
  2581         throws IllegalArgumentException,
       
  2582                RelationNotFoundException {
       
  2583 
       
  2584         if (relationId == null) {
       
  2585             String excMsg = "Invalid parameter.";
       
  2586             throw new IllegalArgumentException(excMsg);
       
  2587         }
       
  2588 
       
  2589         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", relationId);
       
  2590 
       
  2591         // No null relation  accepted, so can use get()
       
  2592         Object rel;
       
  2593         synchronized(myRelId2ObjMap) {
       
  2594             rel = myRelId2ObjMap.get(relationId);
       
  2595         }
       
  2596 
       
  2597         if (rel == null) {
       
  2598             String excMsg = "No relation associated to relation id " + relationId;
       
  2599             throw new RelationNotFoundException(excMsg);
       
  2600         }
       
  2601 
       
  2602         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2603         return rel;
       
  2604     }
       
  2605 
       
  2606     // Adds a new MBean reference (reference to an ObjectName) in the
       
  2607     // referenced MBean map (myRefedMBeanObjName2RelIdsMap).
       
  2608     //
       
  2609     // -param objectName  ObjectName of new referenced MBean
       
  2610     // -param relationId  relation id of the relation where the MBean is
       
  2611     //  referenced
       
  2612     // -param roleName  name of the role where the MBean is referenced
       
  2613     //
       
  2614     // -return boolean:
       
  2615     //  - true  if the MBean was not referenced before, so really a new
       
  2616     //    reference
       
  2617     //  - false else
       
  2618     //
       
  2619     // -exception IllegalArgumentException  if null parameter
       
  2620     private boolean addNewMBeanReference(ObjectName objectName,
       
  2621                                          String relationId,
       
  2622                                          String roleName)
       
  2623         throws IllegalArgumentException {
       
  2624 
       
  2625         if (objectName == null ||
       
  2626             relationId == null ||
       
  2627             roleName == null) {
       
  2628             String excMsg = "Invalid parameter.";
       
  2629             throw new IllegalArgumentException(excMsg);
       
  2630         }
       
  2631 
       
  2632         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
  2633                             objectName, relationId, roleName);
       
  2634 
       
  2635         boolean isNewFlag = false;
       
  2636 
       
  2637         synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  2638 
       
  2639             // Checks if the MBean was already referenced
       
  2640             // No null value allowed, use get() directly
       
  2641             Map<String,List<String>> mbeanRefMap =
       
  2642                 myRefedMBeanObjName2RelIdsMap.get(objectName);
       
  2643 
       
  2644             if (mbeanRefMap == null) {
       
  2645                 // MBean not referenced in any relation yet
       
  2646 
       
  2647                 isNewFlag = true;
       
  2648 
       
  2649                 // List of roles where the MBean is referenced in given
       
  2650                 // relation
       
  2651                 List<String> roleNames = new ArrayList<String>();
       
  2652                 roleNames.add(roleName);
       
  2653 
       
  2654                 // Map of relations where the MBean is referenced
       
  2655                 mbeanRefMap = new HashMap<String,List<String>>();
       
  2656                 mbeanRefMap.put(relationId, roleNames);
       
  2657 
       
  2658                 myRefedMBeanObjName2RelIdsMap.put(objectName, mbeanRefMap);
       
  2659 
       
  2660             } else {
       
  2661                 // MBean already referenced in at least another relation
       
  2662                 // Checks if already referenced in another role in current
       
  2663                 // relation
       
  2664                 List<String> roleNames = mbeanRefMap.get(relationId);
       
  2665 
       
  2666                 if (roleNames == null) {
       
  2667                     // MBean not referenced in current relation
       
  2668 
       
  2669                     // List of roles where the MBean is referenced in given
       
  2670                     // relation
       
  2671                     roleNames = new ArrayList<String>();
       
  2672                     roleNames.add(roleName);
       
  2673 
       
  2674                     // Adds new reference done in current relation
       
  2675                     mbeanRefMap.put(relationId, roleNames);
       
  2676 
       
  2677                 } else {
       
  2678                     // MBean already referenced in current relation in another
       
  2679                     // role
       
  2680                     // Adds new reference done
       
  2681                     roleNames.add(roleName);
       
  2682                 }
       
  2683             }
       
  2684         }
       
  2685 
       
  2686         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2687         return isNewFlag;
       
  2688     }
       
  2689 
       
  2690     // Removes an obsolete MBean reference (reference to an ObjectName) in
       
  2691     // the referenced MBean map (myRefedMBeanObjName2RelIdsMap).
       
  2692     //
       
  2693     // -param objectName  ObjectName of MBean no longer referenced
       
  2694     // -param relationId  relation id of the relation where the MBean was
       
  2695     //  referenced
       
  2696     // -param roleName  name of the role where the MBean was referenced
       
  2697     // -param allRolesFlag  flag, if true removes reference to MBean for all
       
  2698     //  roles in the relation, not only for the one above
       
  2699     //
       
  2700     // -return boolean:
       
  2701     //  - true  if the MBean is no longer reference in any relation
       
  2702     //  - false else
       
  2703     //
       
  2704     // -exception IllegalArgumentException  if null parameter
       
  2705     private boolean removeMBeanReference(ObjectName objectName,
       
  2706                                          String relationId,
       
  2707                                          String roleName,
       
  2708                                          boolean allRolesFlag)
       
  2709         throws IllegalArgumentException {
       
  2710 
       
  2711         if (objectName == null ||
       
  2712             relationId == null ||
       
  2713             roleName == null) {
       
  2714             String excMsg = "Invalid parameter.";
       
  2715             throw new IllegalArgumentException(excMsg);
       
  2716         }
       
  2717 
       
  2718         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2} {3}",
       
  2719                             objectName, relationId, roleName, allRolesFlag);
       
  2720 
       
  2721         boolean noLongerRefFlag = false;
       
  2722 
       
  2723         synchronized(myRefedMBeanObjName2RelIdsMap) {
       
  2724 
       
  2725             // Retrieves the set of relations (designed via their relation ids)
       
  2726             // where the MBean is referenced
       
  2727             // Note that it is possible that the MBean has already been removed
       
  2728             // from the internal map: this is the case when the MBean is
       
  2729             // unregistered, the role is updated, then we arrive here.
       
  2730             Map<String,List<String>> mbeanRefMap =
       
  2731                 (myRefedMBeanObjName2RelIdsMap.get(objectName));
       
  2732 
       
  2733             if (mbeanRefMap == null) {
       
  2734                 // The MBean is no longer referenced
       
  2735                 RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2736                 return true;
       
  2737             }
       
  2738 
       
  2739             List<String> roleNames = null;
       
  2740             if (!allRolesFlag) {
       
  2741                 // Now retrieves the roles of current relation where the MBean
       
  2742                 // was referenced
       
  2743                 roleNames = mbeanRefMap.get(relationId);
       
  2744 
       
  2745                 // Removes obsolete reference to role
       
  2746                 int obsRefIdx = roleNames.indexOf(roleName);
       
  2747                 if (obsRefIdx != -1) {
       
  2748                     roleNames.remove(obsRefIdx);
       
  2749                 }
       
  2750             }
       
  2751 
       
  2752             // Checks if there is still at least one role in current relation
       
  2753             // where the MBean is referenced
       
  2754             if (roleNames.isEmpty() || allRolesFlag) {
       
  2755                 // MBean no longer referenced in current relation: removes
       
  2756                 // entry
       
  2757                 mbeanRefMap.remove(relationId);
       
  2758             }
       
  2759 
       
  2760             // Checks if the MBean is still referenced in at least on relation
       
  2761             if (mbeanRefMap.isEmpty()) {
       
  2762                 // MBean no longer referenced in any relation: removes entry
       
  2763                 myRefedMBeanObjName2RelIdsMap.remove(objectName);
       
  2764                 noLongerRefFlag = true;
       
  2765             }
       
  2766         }
       
  2767 
       
  2768         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2769         return noLongerRefFlag;
       
  2770     }
       
  2771 
       
  2772     // Updates the listener registered to the MBean Server to be informed of
       
  2773     // referenced MBean deregistrations
       
  2774     //
       
  2775     // -param newRefList  ArrayList of ObjectNames for new references done
       
  2776     //  to MBeans (can be null)
       
  2777     // -param obsoleteRefList  ArrayList of ObjectNames for obsolete references
       
  2778     //  to MBeans (can be null)
       
  2779     //
       
  2780     // -exception RelationServiceNotRegisteredException  if the Relation
       
  2781     //  Service is not registered in the MBean Server.
       
  2782     private void updateUnregistrationListener(List<ObjectName> newRefList,
       
  2783                                               List<ObjectName> obsoleteRefList)
       
  2784         throws RelationServiceNotRegisteredException {
       
  2785 
       
  2786         if (newRefList != null && obsoleteRefList != null) {
       
  2787             if (newRefList.isEmpty() && obsoleteRefList.isEmpty()) {
       
  2788                 // Nothing to do :)
       
  2789                 return;
       
  2790             }
       
  2791         }
       
  2792 
       
  2793         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1}",
       
  2794                             newRefList, obsoleteRefList);
       
  2795 
       
  2796         // Can throw RelationServiceNotRegisteredException
       
  2797         isActive();
       
  2798 
       
  2799         if (newRefList != null || obsoleteRefList != null) {
       
  2800 
       
  2801             boolean newListenerFlag = false;
       
  2802             if (myUnregNtfFilter == null) {
       
  2803                 // Initialize it to be able to synchronise it :)
       
  2804                 myUnregNtfFilter = new MBeanServerNotificationFilter();
       
  2805                 newListenerFlag = true;
       
  2806             }
       
  2807 
       
  2808             synchronized(myUnregNtfFilter) {
       
  2809 
       
  2810                 // Enables ObjectNames in newRefList
       
  2811                 if (newRefList != null) {
       
  2812                     for (ObjectName newObjName : newRefList)
       
  2813                         myUnregNtfFilter.enableObjectName(newObjName);
       
  2814                 }
       
  2815 
       
  2816                 if (obsoleteRefList != null) {
       
  2817                     // Disables ObjectNames in obsoleteRefList
       
  2818                     for (ObjectName obsObjName : obsoleteRefList)
       
  2819                         myUnregNtfFilter.disableObjectName(obsObjName);
       
  2820                 }
       
  2821 
       
  2822 // Under test
       
  2823                 if (newListenerFlag) {
       
  2824                     try {
       
  2825                         myMBeanServer.addNotificationListener(
       
  2826                                 MBeanServerDelegate.DELEGATE_NAME,
       
  2827                                 this,
       
  2828                                 myUnregNtfFilter,
       
  2829                                 null);
       
  2830                     } catch (InstanceNotFoundException exc) {
       
  2831                         throw new
       
  2832                        RelationServiceNotRegisteredException(exc.getMessage());
       
  2833                     }
       
  2834                 }
       
  2835 // End test
       
  2836 
       
  2837 
       
  2838 //              if (!newListenerFlag) {
       
  2839                     // The Relation Service was already registered as a
       
  2840                     // listener:
       
  2841                     // removes it
       
  2842                     // Shall not throw InstanceNotFoundException (as the
       
  2843                     // MBean Server Delegate is expected to exist) or
       
  2844                     // ListenerNotFoundException (as it has been checked above
       
  2845                     // that the Relation Service is registered)
       
  2846 //                  try {
       
  2847 //                      myMBeanServer.removeNotificationListener(
       
  2848 //                              MBeanServerDelegate.DELEGATE_NAME,
       
  2849 //                              this);
       
  2850 //                  } catch (InstanceNotFoundException exc1) {
       
  2851 //                      throw new RuntimeException(exc1.getMessage());
       
  2852 //                  } catch (ListenerNotFoundException exc2) {
       
  2853 //                      throw new
       
  2854 //                          RelationServiceNotRegisteredException(exc2.getMessage());
       
  2855 //                  }
       
  2856 //              }
       
  2857 
       
  2858                 // Adds Relation Service with current filter
       
  2859                 // Can throw InstanceNotFoundException if the Relation
       
  2860                 // Service is not registered, to be transformed into
       
  2861                 // RelationServiceNotRegisteredException
       
  2862                 //
       
  2863                 // Assume that there will not be any InstanceNotFoundException
       
  2864                 // for the MBean Server Delegate :)
       
  2865 //              try {
       
  2866 //                  myMBeanServer.addNotificationListener(
       
  2867 //                              MBeanServerDelegate.DELEGATE_NAME,
       
  2868 //                              this,
       
  2869 //                              myUnregNtfFilter,
       
  2870 //                              null);
       
  2871 //              } catch (InstanceNotFoundException exc) {
       
  2872 //                  throw new
       
  2873 //                     RelationServiceNotRegisteredException(exc.getMessage());
       
  2874 //              }
       
  2875             }
       
  2876         }
       
  2877 
       
  2878         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  2879         return;
       
  2880     }
       
  2881 
       
  2882     // Adds a relation (being either a RelationSupport object or an MBean
       
  2883     // referenced using its ObjectName) in the Relation Service.
       
  2884     // Will send a notification RelationNotification with type:
       
  2885     // - RelationNotification.RELATION_BASIC_CREATION for internal relation
       
  2886     //   creation
       
  2887     // - RelationNotification.RELATION_MBEAN_CREATION for an MBean being added
       
  2888     //   as a relation.
       
  2889     //
       
  2890     // -param relationBaseFlag  flag true if the relation is a RelationSupport
       
  2891     //  object, false if it is an MBean
       
  2892     // -param relationObj  RelationSupport object (if relation is internal)
       
  2893     // -param relationObjName  ObjectName of the MBean to be added as a relation
       
  2894     //  (only for the relation MBean)
       
  2895     // -param relationId  relation identifier, to uniquely identify the relation
       
  2896     //  inside the Relation Service
       
  2897     // -param relationTypeName  name of the relation type (has to be created
       
  2898     //  in the Relation Service)
       
  2899     // -param roleList  role list to initialize roles of the relation
       
  2900     //  (can be null)
       
  2901     //
       
  2902     // -exception IllegalArgumentException  if null paramater
       
  2903     // -exception RelationServiceNotRegisteredException  if the Relation
       
  2904     //  Service is not registered in the MBean Server
       
  2905     // -exception RoleNotFoundException  if a value is provided for a role
       
  2906     //  that does not exist in the relation type
       
  2907     // -exception InvalidRelationIdException  if relation id already used
       
  2908     // -exception RelationTypeNotFoundException  if relation type not known in
       
  2909     //  Relation Service
       
  2910     // -exception InvalidRoleValueException if:
       
  2911     //  - the same role name is used for two different roles
       
  2912     //  - the number of referenced MBeans in given value is less than
       
  2913     //    expected minimum degree
       
  2914     //  - the number of referenced MBeans in provided value exceeds expected
       
  2915     //    maximum degree
       
  2916     //  - one referenced MBean in the value is not an Object of the MBean
       
  2917     //    class expected for that role
       
  2918     //  - an MBean provided for that role does not exist
       
  2919     private void addRelationInt(boolean relationBaseFlag,
       
  2920                                 RelationSupport relationObj,
       
  2921                                 ObjectName relationObjName,
       
  2922                                 String relationId,
       
  2923                                 String relationTypeName,
       
  2924                                 RoleList roleList)
       
  2925         throws IllegalArgumentException,
       
  2926                RelationServiceNotRegisteredException,
       
  2927                RoleNotFoundException,
       
  2928                InvalidRelationIdException,
       
  2929                RelationTypeNotFoundException,
       
  2930                InvalidRoleValueException {
       
  2931 
       
  2932         if (relationId == null ||
       
  2933             relationTypeName == null ||
       
  2934             (relationBaseFlag &&
       
  2935              (relationObj == null ||
       
  2936               relationObjName != null)) ||
       
  2937             (!relationBaseFlag &&
       
  2938              (relationObjName == null ||
       
  2939               relationObj != null))) {
       
  2940             String excMsg = "Invalid parameter.";
       
  2941             throw new IllegalArgumentException(excMsg);
       
  2942         }
       
  2943 
       
  2944         RELATION_LOGGER.log(Level.TRACE,
       
  2945                             "ENTRY {0} {1} {2} {3} {4} {5}",
       
  2946                             relationBaseFlag, relationObj, relationObjName,
       
  2947                             relationId, relationTypeName, roleList);
       
  2948 
       
  2949         // Can throw RelationServiceNotRegisteredException
       
  2950         isActive();
       
  2951 
       
  2952         // Checks if there is already a relation with given id
       
  2953         try {
       
  2954             // Can throw a RelationNotFoundException (in fact should :)
       
  2955             Object rel = getRelation(relationId);
       
  2956 
       
  2957             if (rel != null) {
       
  2958                 // There is already a relation with that id
       
  2959                 String excMsg = "There is already a relation with id ";
       
  2960                 StringBuilder excMsgStrB = new StringBuilder(excMsg);
       
  2961                 excMsgStrB.append(relationId);
       
  2962                 throw new InvalidRelationIdException(excMsgStrB.toString());
       
  2963             }
       
  2964         } catch (RelationNotFoundException exc) {
       
  2965             // OK : The Relation could not be found.
       
  2966         }
       
  2967 
       
  2968         // Retrieves the relation type
       
  2969         // Can throw RelationTypeNotFoundException
       
  2970         RelationType relType = getRelationType(relationTypeName);
       
  2971 
       
  2972         // Checks that each provided role conforms to its role info provided in
       
  2973         // the relation type
       
  2974         // First retrieves a local list of the role infos of the relation type
       
  2975         // to see which roles have not been initialized
       
  2976         // Note: no need to test if list not null before cloning, not allowed
       
  2977         //       to have an empty relation type.
       
  2978         List<RoleInfo> roleInfoList = new ArrayList<RoleInfo>(relType.getRoleInfos());
       
  2979 
       
  2980         if (roleList != null) {
       
  2981 
       
  2982             for (Role currRole : roleList.asList()) {
       
  2983                 String currRoleName = currRole.getRoleName();
       
  2984                 List<ObjectName> currRoleValue = currRole.getRoleValue();
       
  2985                 // Retrieves corresponding role info
       
  2986                 // Can throw a RoleInfoNotFoundException to be converted into a
       
  2987                 // RoleNotFoundException
       
  2988                 RoleInfo roleInfo;
       
  2989                 try {
       
  2990                     roleInfo = relType.getRoleInfo(currRoleName);
       
  2991                 } catch (RoleInfoNotFoundException exc) {
       
  2992                     throw new RoleNotFoundException(exc.getMessage());
       
  2993                 }
       
  2994 
       
  2995                 // Checks that role conforms to role info,
       
  2996                 Integer status = checkRoleInt(2,
       
  2997                                               currRoleName,
       
  2998                                               currRoleValue,
       
  2999                                               roleInfo,
       
  3000                                               false);
       
  3001                 int pbType = status.intValue();
       
  3002                 if (pbType != 0) {
       
  3003                     // A problem has occurred: throws appropriate exception
       
  3004                     // here InvalidRoleValueException
       
  3005                     throwRoleProblemException(pbType, currRoleName);
       
  3006                 }
       
  3007 
       
  3008                 // Removes role info for that list from list of role infos for
       
  3009                 // roles to be defaulted
       
  3010                 int roleInfoIdx = roleInfoList.indexOf(roleInfo);
       
  3011                 // Note: no need to check if != -1, MUST be there :)
       
  3012                 roleInfoList.remove(roleInfoIdx);
       
  3013             }
       
  3014         }
       
  3015 
       
  3016         // Initializes roles not initialized by roleList
       
  3017         // Can throw InvalidRoleValueException
       
  3018         initializeMissingRoles(relationBaseFlag,
       
  3019                                relationObj,
       
  3020                                relationObjName,
       
  3021                                relationId,
       
  3022                                relationTypeName,
       
  3023                                roleInfoList);
       
  3024 
       
  3025         // Creation of relation successfull!!!!
       
  3026 
       
  3027         // Updates internal maps
       
  3028         // Relation id to object map
       
  3029         synchronized(myRelId2ObjMap) {
       
  3030             if (relationBaseFlag) {
       
  3031                 // Note: do not clone relation object, created by us :)
       
  3032                 myRelId2ObjMap.put(relationId, relationObj);
       
  3033             } else {
       
  3034                 myRelId2ObjMap.put(relationId, relationObjName);
       
  3035             }
       
  3036         }
       
  3037 
       
  3038         // Relation id to relation type name map
       
  3039         synchronized(myRelId2RelTypeMap) {
       
  3040             myRelId2RelTypeMap.put(relationId,
       
  3041                                    relationTypeName);
       
  3042         }
       
  3043 
       
  3044         // Relation type to relation id map
       
  3045         synchronized(myRelType2RelIdsMap) {
       
  3046             List<String> relIdList =
       
  3047                 myRelType2RelIdsMap.get(relationTypeName);
       
  3048             boolean firstRelFlag = false;
       
  3049             if (relIdList == null) {
       
  3050                 firstRelFlag = true;
       
  3051                 relIdList = new ArrayList<String>();
       
  3052             }
       
  3053             relIdList.add(relationId);
       
  3054             if (firstRelFlag) {
       
  3055                 myRelType2RelIdsMap.put(relationTypeName, relIdList);
       
  3056             }
       
  3057         }
       
  3058 
       
  3059         // Referenced MBean to relation id map
       
  3060         // Only role list parameter used, as default initialization of roles
       
  3061         // done automatically in initializeMissingRoles() sets each
       
  3062         // uninitialized role to an empty value.
       
  3063         for (Role currRole : roleList.asList()) {
       
  3064             // Creates a dummy empty ArrayList of ObjectNames to be the old
       
  3065             // role value :)
       
  3066             List<ObjectName> dummyList = new ArrayList<ObjectName>();
       
  3067             // Will not throw a RelationNotFoundException (as the RelId2Obj map
       
  3068             // has been updated above) so catch it :)
       
  3069             try {
       
  3070                 updateRoleMap(relationId, currRole, dummyList);
       
  3071 
       
  3072             } catch (RelationNotFoundException exc) {
       
  3073                 // OK : The Relation could not be found.
       
  3074             }
       
  3075         }
       
  3076 
       
  3077         // Sends a notification for relation creation
       
  3078         // Will not throw RelationNotFoundException so catch it :)
       
  3079         try {
       
  3080             sendRelationCreationNotification(relationId);
       
  3081 
       
  3082         } catch (RelationNotFoundException exc) {
       
  3083             // OK : The Relation could not be found.
       
  3084         }
       
  3085 
       
  3086         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3087         return;
       
  3088     }
       
  3089 
       
  3090     // Checks that given role conforms to given role info.
       
  3091     //
       
  3092     // -param chkType  type of check:
       
  3093     //  - 1: read, just check read access
       
  3094     //  - 2: write, check value and write access if writeChkFlag
       
  3095     // -param roleName  role name
       
  3096     // -param roleValue  role value
       
  3097     // -param roleInfo  corresponding role info
       
  3098     // -param writeChkFlag  boolean to specify a current write access and
       
  3099     //  to check it
       
  3100     //
       
  3101     // -return Integer with value:
       
  3102     //  - 0: ok
       
  3103     //  - RoleStatus.NO_ROLE_WITH_NAME
       
  3104     //  - RoleStatus.ROLE_NOT_READABLE
       
  3105     //  - RoleStatus.ROLE_NOT_WRITABLE
       
  3106     //  - RoleStatus.LESS_THAN_MIN_ROLE_DEGREE
       
  3107     //  - RoleStatus.MORE_THAN_MAX_ROLE_DEGREE
       
  3108     //  - RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS
       
  3109     //  - RoleStatus.REF_MBEAN_NOT_REGISTERED
       
  3110     //
       
  3111     // -exception IllegalArgumentException  if null parameter
       
  3112     private Integer checkRoleInt(int chkType,
       
  3113                                  String roleName,
       
  3114                                  List<ObjectName> roleValue,
       
  3115                                  RoleInfo roleInfo,
       
  3116                                  boolean writeChkFlag)
       
  3117         throws IllegalArgumentException {
       
  3118 
       
  3119         if (roleName == null ||
       
  3120             roleInfo == null ||
       
  3121             (chkType == 2 && roleValue == null)) {
       
  3122             String excMsg = "Invalid parameter.";
       
  3123             throw new IllegalArgumentException(excMsg);
       
  3124         }
       
  3125 
       
  3126         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2} {3} {4}",
       
  3127                             chkType, roleName, roleValue, roleInfo, writeChkFlag);
       
  3128 
       
  3129         // Compares names
       
  3130         String expName = roleInfo.getName();
       
  3131         if (!(roleName.equals(expName))) {
       
  3132             RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3133             return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
       
  3134         }
       
  3135 
       
  3136         // Checks read access if required
       
  3137         if (chkType == 1) {
       
  3138             boolean isReadable = roleInfo.isReadable();
       
  3139             if (!isReadable) {
       
  3140                 RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3141                 return Integer.valueOf(RoleStatus.ROLE_NOT_READABLE);
       
  3142             } else {
       
  3143                 // End of check :)
       
  3144                 RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3145                 return 0;
       
  3146             }
       
  3147         }
       
  3148 
       
  3149         // Checks write access if required
       
  3150         if (writeChkFlag) {
       
  3151             boolean isWritable = roleInfo.isWritable();
       
  3152             if (!isWritable) {
       
  3153                 RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3154                 return RoleStatus.ROLE_NOT_WRITABLE;
       
  3155             }
       
  3156         }
       
  3157 
       
  3158         int refNbr = roleValue.size();
       
  3159 
       
  3160         // Checks minimum cardinality
       
  3161         boolean chkMinFlag = roleInfo.checkMinDegree(refNbr);
       
  3162         if (!chkMinFlag) {
       
  3163             RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3164             return RoleStatus.LESS_THAN_MIN_ROLE_DEGREE;
       
  3165         }
       
  3166 
       
  3167         // Checks maximum cardinality
       
  3168         boolean chkMaxFlag = roleInfo.checkMaxDegree(refNbr);
       
  3169         if (!chkMaxFlag) {
       
  3170             RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3171             return RoleStatus.MORE_THAN_MAX_ROLE_DEGREE;
       
  3172         }
       
  3173 
       
  3174         // Verifies that each referenced MBean is registered in the MBean
       
  3175         // Server and that it is an instance of the class specified in the
       
  3176         // role info, or of a subclass of it
       
  3177         // Note that here again this is under the assumption that
       
  3178         // referenced MBeans, relation MBeans and the Relation Service are
       
  3179         // registered in the same MBean Server.
       
  3180         String expClassName = roleInfo.getRefMBeanClassName();
       
  3181 
       
  3182         for (ObjectName currObjName : roleValue) {
       
  3183 
       
  3184             // Checks it is registered
       
  3185             if (currObjName == null) {
       
  3186                 RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3187                 return RoleStatus.REF_MBEAN_NOT_REGISTERED;
       
  3188             }
       
  3189 
       
  3190             // Checks if it is of the correct class
       
  3191             // Can throw an InstanceNotFoundException, if MBean not registered
       
  3192             try {
       
  3193                 boolean classSts = myMBeanServer.isInstanceOf(currObjName,
       
  3194                                                               expClassName);
       
  3195                 if (!classSts) {
       
  3196                     RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3197                     return RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS;
       
  3198                 }
       
  3199 
       
  3200             } catch (InstanceNotFoundException exc) {
       
  3201                 RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3202                 return RoleStatus.REF_MBEAN_NOT_REGISTERED;
       
  3203             }
       
  3204         }
       
  3205 
       
  3206         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3207         return 0;
       
  3208     }
       
  3209 
       
  3210 
       
  3211     // Initializes roles associated to given role infos to default value (empty
       
  3212     // ArrayList of ObjectNames) in given relation.
       
  3213     // It will succeed for every role except if the role info has a minimum
       
  3214     // cardinality greater than 0. In that case, an InvalidRoleValueException
       
  3215     // will be raised.
       
  3216     //
       
  3217     // -param relationBaseFlag  flag true if the relation is a RelationSupport
       
  3218     //  object, false if it is an MBean
       
  3219     // -param relationObj  RelationSupport object (if relation is internal)
       
  3220     // -param relationObjName  ObjectName of the MBean to be added as a relation
       
  3221     //  (only for the relation MBean)
       
  3222     // -param relationId  relation id
       
  3223     // -param relationTypeName  name of the relation type (has to be created
       
  3224     //  in the Relation Service)
       
  3225     // -param roleInfoList  list of role infos for roles to be defaulted
       
  3226     //
       
  3227     // -exception IllegalArgumentException  if null paramater
       
  3228     // -exception RelationServiceNotRegisteredException  if the Relation
       
  3229     //  Service is not registered in the MBean Server
       
  3230     // -exception InvalidRoleValueException  if role must have a non-empty
       
  3231     //  value
       
  3232 
       
  3233     // Revisit [cebro] Handle CIM qualifiers as REQUIRED to detect roles which
       
  3234     //    should have been initialized by the user
       
  3235     private void initializeMissingRoles(boolean relationBaseFlag,
       
  3236                                         RelationSupport relationObj,
       
  3237                                         ObjectName relationObjName,
       
  3238                                         String relationId,
       
  3239                                         String relationTypeName,
       
  3240                                         List<RoleInfo> roleInfoList)
       
  3241         throws IllegalArgumentException,
       
  3242                RelationServiceNotRegisteredException,
       
  3243                InvalidRoleValueException {
       
  3244 
       
  3245         if ((relationBaseFlag &&
       
  3246              (relationObj == null ||
       
  3247               relationObjName != null)) ||
       
  3248             (!relationBaseFlag &&
       
  3249              (relationObjName == null ||
       
  3250               relationObj != null)) ||
       
  3251             relationId == null ||
       
  3252             relationTypeName == null ||
       
  3253             roleInfoList == null) {
       
  3254             String excMsg = "Invalid parameter.";
       
  3255             throw new IllegalArgumentException(excMsg);
       
  3256         }
       
  3257 
       
  3258         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2} {3} {4} {5}",
       
  3259                             relationBaseFlag, relationObj, relationObjName,
       
  3260                             relationId, relationTypeName, roleInfoList);
       
  3261 
       
  3262         // Can throw RelationServiceNotRegisteredException
       
  3263         isActive();
       
  3264 
       
  3265         // For each role info (corresponding to a role not initialized by the
       
  3266         // role list provided by the user), try to set in the relation a role
       
  3267         // with an empty list of ObjectNames.
       
  3268         // A check is performed to verify that the role can be set to an
       
  3269         // empty value, according to its minimum cardinality
       
  3270         for (RoleInfo currRoleInfo : roleInfoList) {
       
  3271 
       
  3272             String roleName = currRoleInfo.getName();
       
  3273 
       
  3274             // Creates an empty value
       
  3275             List<ObjectName> emptyValue = new ArrayList<ObjectName>();
       
  3276             // Creates a role
       
  3277             Role role = new Role(roleName, emptyValue);
       
  3278 
       
  3279             if (relationBaseFlag) {
       
  3280 
       
  3281                 // Internal relation
       
  3282                 // Can throw InvalidRoleValueException
       
  3283                 //
       
  3284                 // Will not throw RoleNotFoundException (role to be
       
  3285                 // initialized), or RelationNotFoundException, or
       
  3286                 // RelationTypeNotFoundException
       
  3287                 try {
       
  3288                     relationObj.setRoleInt(role, true, this, false);
       
  3289 
       
  3290                 } catch (RoleNotFoundException exc1) {
       
  3291                     throw new RuntimeException(exc1.getMessage());
       
  3292                 } catch (RelationNotFoundException exc2) {
       
  3293                     throw new RuntimeException(exc2.getMessage());
       
  3294                 } catch (RelationTypeNotFoundException exc3) {
       
  3295                     throw new RuntimeException(exc3.getMessage());
       
  3296                 }
       
  3297 
       
  3298             } else {
       
  3299 
       
  3300                 // Relation is an MBean
       
  3301                 // Use standard setRole()
       
  3302                 Object[] params = new Object[1];
       
  3303                 params[0] = role;
       
  3304                 String[] signature = new String[1];
       
  3305                 signature[0] = "javax.management.relation.Role";
       
  3306                 // Can throw MBeanException wrapping
       
  3307                 // InvalidRoleValueException. Returns the target exception to
       
  3308                 // be homogeneous.
       
  3309                 //
       
  3310                 // Will not throw MBeanException (wrapping
       
  3311                 // RoleNotFoundException or MBeanException) or
       
  3312                 // InstanceNotFoundException, or ReflectionException
       
  3313                 //
       
  3314                 // Again here the assumption is that the Relation Service and
       
  3315                 // the relation MBeans are registered in the same MBean Server.
       
  3316                 try {
       
  3317                     myMBeanServer.setAttribute(relationObjName,
       
  3318                                                new Attribute("Role", role));
       
  3319 
       
  3320                 } catch (InstanceNotFoundException exc1) {
       
  3321                     throw new RuntimeException(exc1.getMessage());
       
  3322                 } catch (ReflectionException exc3) {
       
  3323                     throw new RuntimeException(exc3.getMessage());
       
  3324                 } catch (MBeanException exc2) {
       
  3325                     Exception wrappedExc = exc2.getTargetException();
       
  3326                     if (wrappedExc instanceof InvalidRoleValueException) {
       
  3327                         throw ((InvalidRoleValueException)wrappedExc);
       
  3328                     } else {
       
  3329                         throw new RuntimeException(wrappedExc.getMessage());
       
  3330                     }
       
  3331                 } catch (AttributeNotFoundException exc4) {
       
  3332                   throw new RuntimeException(exc4.getMessage());
       
  3333                 } catch (InvalidAttributeValueException exc5) {
       
  3334                   throw new RuntimeException(exc5.getMessage());
       
  3335                 }
       
  3336             }
       
  3337         }
       
  3338 
       
  3339         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3340         return;
       
  3341     }
       
  3342 
       
  3343     // Throws an exception corresponding to a given problem type
       
  3344     //
       
  3345     // -param pbType  possible problem, defined in RoleUnresolved
       
  3346     // -param roleName  role name
       
  3347     //
       
  3348     // -exception IllegalArgumentException  if null parameter
       
  3349     // -exception RoleNotFoundException  for problems:
       
  3350     //  - NO_ROLE_WITH_NAME
       
  3351     //  - ROLE_NOT_READABLE
       
  3352     //  - ROLE_NOT_WRITABLE
       
  3353     // -exception InvalidRoleValueException  for problems:
       
  3354     //  - LESS_THAN_MIN_ROLE_DEGREE
       
  3355     //  - MORE_THAN_MAX_ROLE_DEGREE
       
  3356     //  - REF_MBEAN_OF_INCORRECT_CLASS
       
  3357     //  - REF_MBEAN_NOT_REGISTERED
       
  3358     static void throwRoleProblemException(int pbType,
       
  3359                                           String roleName)
       
  3360         throws IllegalArgumentException,
       
  3361                RoleNotFoundException,
       
  3362                InvalidRoleValueException {
       
  3363 
       
  3364         if (roleName == null) {
       
  3365             String excMsg = "Invalid parameter.";
       
  3366             throw new IllegalArgumentException(excMsg);
       
  3367         }
       
  3368 
       
  3369         // Exception type: 1 = RoleNotFoundException
       
  3370         //                 2 = InvalidRoleValueException
       
  3371         int excType = 0;
       
  3372 
       
  3373         String excMsgPart = null;
       
  3374 
       
  3375         switch (pbType) {
       
  3376         case RoleStatus.NO_ROLE_WITH_NAME:
       
  3377             excMsgPart = " does not exist in relation.";
       
  3378             excType = 1;
       
  3379             break;
       
  3380         case RoleStatus.ROLE_NOT_READABLE:
       
  3381             excMsgPart = " is not readable.";
       
  3382             excType = 1;
       
  3383             break;
       
  3384         case RoleStatus.ROLE_NOT_WRITABLE:
       
  3385             excMsgPart = " is not writable.";
       
  3386             excType = 1;
       
  3387             break;
       
  3388         case RoleStatus.LESS_THAN_MIN_ROLE_DEGREE:
       
  3389             excMsgPart = " has a number of MBean references less than the expected minimum degree.";
       
  3390             excType = 2;
       
  3391             break;
       
  3392         case RoleStatus.MORE_THAN_MAX_ROLE_DEGREE:
       
  3393             excMsgPart = " has a number of MBean references greater than the expected maximum degree.";
       
  3394             excType = 2;
       
  3395             break;
       
  3396         case RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS:
       
  3397             excMsgPart = " has an MBean reference to an MBean not of the expected class of references for that role.";
       
  3398             excType = 2;
       
  3399             break;
       
  3400         case RoleStatus.REF_MBEAN_NOT_REGISTERED:
       
  3401             excMsgPart = " has a reference to null or to an MBean not registered.";
       
  3402             excType = 2;
       
  3403             break;
       
  3404         }
       
  3405         // No default as we must have been in one of those cases
       
  3406 
       
  3407         StringBuilder excMsgStrB = new StringBuilder(roleName);
       
  3408         excMsgStrB.append(excMsgPart);
       
  3409         String excMsg = excMsgStrB.toString();
       
  3410         if (excType == 1) {
       
  3411             throw new RoleNotFoundException(excMsg);
       
  3412 
       
  3413         } else if (excType == 2) {
       
  3414             throw new InvalidRoleValueException(excMsg);
       
  3415         }
       
  3416     }
       
  3417 
       
  3418     // Sends a notification of given type, with given parameters
       
  3419     //
       
  3420     // -param intNtfType  integer to represent notification type:
       
  3421     //  - 1 : create
       
  3422     //  - 2 : update
       
  3423     //  - 3 : delete
       
  3424     // -param message  human-readable message
       
  3425     // -param relationId  relation id of the created/updated/deleted relation
       
  3426     // -param unregMBeanList  list of ObjectNames of referenced MBeans
       
  3427     //  expected to be unregistered due to relation removal (only for removal,
       
  3428     //  due to CIM qualifiers, can be null)
       
  3429     // -param roleName  role name
       
  3430     // -param roleNewValue  role new value (ArrayList of ObjectNames)
       
  3431     // -param oldValue  old role value (ArrayList of ObjectNames)
       
  3432     //
       
  3433     // -exception IllegalArgument  if null parameter
       
  3434     // -exception RelationNotFoundException  if no relation for given id
       
  3435     private void sendNotificationInt(int intNtfType,
       
  3436                                      String message,
       
  3437                                      String relationId,
       
  3438                                      List<ObjectName> unregMBeanList,
       
  3439                                      String roleName,
       
  3440                                      List<ObjectName> roleNewValue,
       
  3441                                      List<ObjectName> oldValue)
       
  3442         throws IllegalArgumentException,
       
  3443                RelationNotFoundException {
       
  3444 
       
  3445         if (message == null ||
       
  3446             relationId == null ||
       
  3447             (intNtfType != 3 && unregMBeanList != null) ||
       
  3448             (intNtfType == 2 &&
       
  3449              (roleName == null ||
       
  3450               roleNewValue == null ||
       
  3451               oldValue == null))) {
       
  3452             String excMsg = "Invalid parameter.";
       
  3453             throw new IllegalArgumentException(excMsg);
       
  3454         }
       
  3455 
       
  3456         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2} {3} {4} {5} {6}",
       
  3457                             intNtfType, message, relationId, unregMBeanList,
       
  3458                             roleName, roleNewValue, oldValue);
       
  3459 
       
  3460         // Relation type name
       
  3461         // Note: do not use getRelationTypeName() as if it is a relation MBean
       
  3462         //       it is already unregistered.
       
  3463         String relTypeName;
       
  3464         synchronized(myRelId2RelTypeMap) {
       
  3465             relTypeName = (myRelId2RelTypeMap.get(relationId));
       
  3466         }
       
  3467 
       
  3468         // ObjectName (for a relation MBean)
       
  3469         // Can also throw a RelationNotFoundException, but detected above
       
  3470         ObjectName relObjName = isRelationMBean(relationId);
       
  3471 
       
  3472         String ntfType = null;
       
  3473         if (relObjName != null) {
       
  3474             switch (intNtfType) {
       
  3475             case 1:
       
  3476                 ntfType = RelationNotification.RELATION_MBEAN_CREATION;
       
  3477                 break;
       
  3478             case 2:
       
  3479                 ntfType = RelationNotification.RELATION_MBEAN_UPDATE;
       
  3480                 break;
       
  3481             case 3:
       
  3482                 ntfType = RelationNotification.RELATION_MBEAN_REMOVAL;
       
  3483                 break;
       
  3484             }
       
  3485         } else {
       
  3486             switch (intNtfType) {
       
  3487             case 1:
       
  3488                 ntfType = RelationNotification.RELATION_BASIC_CREATION;
       
  3489                 break;
       
  3490             case 2:
       
  3491                 ntfType = RelationNotification.RELATION_BASIC_UPDATE;
       
  3492                 break;
       
  3493             case 3:
       
  3494                 ntfType = RelationNotification.RELATION_BASIC_REMOVAL;
       
  3495                 break;
       
  3496             }
       
  3497         }
       
  3498 
       
  3499         // Sequence number
       
  3500         Long seqNo = atomicSeqNo.incrementAndGet();
       
  3501 
       
  3502         // Timestamp
       
  3503         Date currDate = new Date();
       
  3504         long timeStamp = currDate.getTime();
       
  3505 
       
  3506         RelationNotification ntf = null;
       
  3507 
       
  3508         if (ntfType.equals(RelationNotification.RELATION_BASIC_CREATION) ||
       
  3509             ntfType.equals(RelationNotification.RELATION_MBEAN_CREATION) ||
       
  3510             ntfType.equals(RelationNotification.RELATION_BASIC_REMOVAL) ||
       
  3511             ntfType.equals(RelationNotification.RELATION_MBEAN_REMOVAL))
       
  3512 
       
  3513             // Creation or removal
       
  3514             ntf = new RelationNotification(ntfType,
       
  3515                                            this,
       
  3516                                            seqNo.longValue(),
       
  3517                                            timeStamp,
       
  3518                                            message,
       
  3519                                            relationId,
       
  3520                                            relTypeName,
       
  3521                                            relObjName,
       
  3522                                            unregMBeanList);
       
  3523 
       
  3524         else if (ntfType.equals(RelationNotification.RELATION_BASIC_UPDATE)
       
  3525                  ||
       
  3526                  ntfType.equals(RelationNotification.RELATION_MBEAN_UPDATE))
       
  3527             {
       
  3528                 // Update
       
  3529                 ntf = new RelationNotification(ntfType,
       
  3530                                                this,
       
  3531                                                seqNo.longValue(),
       
  3532                                                timeStamp,
       
  3533                                                message,
       
  3534                                                relationId,
       
  3535                                                relTypeName,
       
  3536                                                relObjName,
       
  3537                                                roleName,
       
  3538                                                roleNewValue,
       
  3539                                                oldValue);
       
  3540             }
       
  3541 
       
  3542         sendNotification(ntf);
       
  3543 
       
  3544         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3545         return;
       
  3546     }
       
  3547 
       
  3548     // Checks, for the unregistration of an MBean referenced in the roles given
       
  3549     // in parameter, if the relation has to be removed or not, regarding
       
  3550     // expected minimum role cardinality and current number of
       
  3551     // references in each role after removal of the current one.
       
  3552     // If the relation is kept, calls handleMBeanUnregistration() callback of
       
  3553     // the relation to update it.
       
  3554     //
       
  3555     // -param relationId  relation id
       
  3556     // -param objectName  ObjectName of the unregistered MBean
       
  3557     // -param roleNameList  list of names of roles where the unregistered
       
  3558     //  MBean is referenced.
       
  3559     //
       
  3560     // -exception IllegalArgumentException  if null parameter
       
  3561     // -exception RelationServiceNotRegisteredException  if the Relation
       
  3562     //  Service is not registered in the MBean Server
       
  3563     // -exception RelationNotFoundException  if unknown relation id
       
  3564     // -exception RoleNotFoundException  if one role given as parameter does
       
  3565     //  not exist in the relation
       
  3566     private void handleReferenceUnregistration(String relationId,
       
  3567                                                ObjectName objectName,
       
  3568                                                List<String> roleNameList)
       
  3569         throws IllegalArgumentException,
       
  3570                RelationServiceNotRegisteredException,
       
  3571                RelationNotFoundException,
       
  3572                RoleNotFoundException {
       
  3573 
       
  3574         if (relationId == null ||
       
  3575             roleNameList == null ||
       
  3576             objectName == null) {
       
  3577             String excMsg = "Invalid parameter.";
       
  3578             throw new IllegalArgumentException(excMsg);
       
  3579         }
       
  3580 
       
  3581         RELATION_LOGGER.log(Level.TRACE, "ENTRY {0} {1} {2}",
       
  3582                             relationId, objectName, roleNameList);
       
  3583 
       
  3584         // Can throw RelationServiceNotRegisteredException
       
  3585         isActive();
       
  3586 
       
  3587         // Retrieves the relation type name of the relation
       
  3588         // Can throw RelationNotFoundException
       
  3589         String currRelTypeName = getRelationTypeName(relationId);
       
  3590 
       
  3591         // Retrieves the relation
       
  3592         // Can throw RelationNotFoundException, but already detected above
       
  3593         Object relObj = getRelation(relationId);
       
  3594 
       
  3595         // Flag to specify if the relation has to be deleted
       
  3596         boolean deleteRelFlag = false;
       
  3597 
       
  3598         for (String currRoleName : roleNameList) {
       
  3599 
       
  3600             if (deleteRelFlag) {
       
  3601                 break;
       
  3602             }
       
  3603 
       
  3604             // Retrieves number of MBeans currently referenced in role
       
  3605             // BEWARE! Do not use getRole() as role may be not readable
       
  3606             //
       
  3607             // Can throw RelationNotFoundException (but already checked),
       
  3608             // RoleNotFoundException
       
  3609             int currRoleRefNbr =
       
  3610                 (getRoleCardinality(relationId, currRoleName)).intValue();
       
  3611 
       
  3612             // Retrieves new number of element in role
       
  3613             int currRoleNewRefNbr = currRoleRefNbr - 1;
       
  3614 
       
  3615             // Retrieves role info for that role
       
  3616             //
       
  3617             // Shall not throw RelationTypeNotFoundException or
       
  3618             // RoleInfoNotFoundException
       
  3619             RoleInfo currRoleInfo;
       
  3620             try {
       
  3621                 currRoleInfo = getRoleInfo(currRelTypeName,
       
  3622                                            currRoleName);
       
  3623             } catch (RelationTypeNotFoundException exc1) {
       
  3624                 throw new RuntimeException(exc1.getMessage());
       
  3625             } catch (RoleInfoNotFoundException exc2) {
       
  3626                 throw new RuntimeException(exc2.getMessage());
       
  3627             }
       
  3628 
       
  3629             // Checks with expected minimum number of elements
       
  3630             boolean chkMinFlag = currRoleInfo.checkMinDegree(currRoleNewRefNbr);
       
  3631 
       
  3632             if (!chkMinFlag) {
       
  3633                 // The relation has to be deleted
       
  3634                 deleteRelFlag = true;
       
  3635             }
       
  3636         }
       
  3637 
       
  3638         if (deleteRelFlag) {
       
  3639             // Removes the relation
       
  3640             removeRelation(relationId);
       
  3641 
       
  3642         } else {
       
  3643 
       
  3644             // Updates each role in the relation using
       
  3645             // handleMBeanUnregistration() callback
       
  3646             //
       
  3647             // BEWARE: this roleNameList list MUST BE A COPY of a role name
       
  3648             //         list for a referenced MBean in a relation, NOT a
       
  3649             //         reference to an original one part of the
       
  3650             //         myRefedMBeanObjName2RelIdsMap!!!! Because each role
       
  3651             //         which name is in that list will be updated (potentially
       
  3652             //         using setRole(). So the Relation Service will update the
       
  3653             //         myRefedMBeanObjName2RelIdsMap to refelect the new role
       
  3654             //         value!
       
  3655             for (String currRoleName : roleNameList) {
       
  3656 
       
  3657                 if (relObj instanceof RelationSupport) {
       
  3658                     // Internal relation
       
  3659                     // Can throw RoleNotFoundException (but already checked)
       
  3660                     //
       
  3661                     // Shall not throw
       
  3662                     // RelationTypeNotFoundException,
       
  3663                     // InvalidRoleValueException (value was correct, removing
       
  3664                     // one reference shall not invalidate it, else detected
       
  3665                     // above)
       
  3666                     try {
       
  3667                         ((RelationSupport)relObj).handleMBeanUnregistrationInt(
       
  3668                                                   objectName,
       
  3669                                                   currRoleName,
       
  3670                                                   true,
       
  3671                                                   this);
       
  3672                     } catch (RelationTypeNotFoundException exc3) {
       
  3673                         throw new RuntimeException(exc3.getMessage());
       
  3674                     } catch (InvalidRoleValueException exc4) {
       
  3675                         throw new RuntimeException(exc4.getMessage());
       
  3676                     }
       
  3677 
       
  3678                 } else {
       
  3679                     // Relation MBean
       
  3680                     Object[] params = new Object[2];
       
  3681                     params[0] = objectName;
       
  3682                     params[1] = currRoleName;
       
  3683                     String[] signature = new String[2];
       
  3684                     signature[0] = "javax.management.ObjectName";
       
  3685                     signature[1] = "java.lang.String";
       
  3686                     // Shall not throw InstanceNotFoundException, or
       
  3687                     // MBeanException (wrapping RoleNotFoundException or
       
  3688                     // MBeanException or InvalidRoleValueException) or
       
  3689                     // ReflectionException
       
  3690                     try {
       
  3691                         myMBeanServer.invoke(((ObjectName)relObj),
       
  3692                                              "handleMBeanUnregistration",
       
  3693                                              params,
       
  3694                                              signature);
       
  3695                     } catch (InstanceNotFoundException exc1) {
       
  3696                         throw new RuntimeException(exc1.getMessage());
       
  3697                     } catch (ReflectionException exc3) {
       
  3698                         throw new RuntimeException(exc3.getMessage());
       
  3699                     } catch (MBeanException exc2) {
       
  3700                         Exception wrappedExc = exc2.getTargetException();
       
  3701                         throw new RuntimeException(wrappedExc.getMessage());
       
  3702                     }
       
  3703 
       
  3704                 }
       
  3705             }
       
  3706         }
       
  3707 
       
  3708         RELATION_LOGGER.log(Level.TRACE, "RETURN");
       
  3709         return;
       
  3710     }
       
  3711 }