/* * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.management.relation; import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER; import static com.sun.jmx.mbeanserver.Util.cast; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; import javax.management.MBeanServerNotification; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; /** * The Relation Service is in charge of creating and deleting relation types * and relations, of handling the consistency and of providing query * mechanisms. * <P>It implements the NotificationBroadcaster by extending * NotificationBroadcasterSupport to send notifications when a relation is * removed from it. * <P>It implements the NotificationListener interface to be able to receive * notifications concerning unregistration of MBeans referenced in relation * roles and of relation MBeans. * <P>It implements the MBeanRegistration interface to be able to retrieve * its ObjectName and MBean Server. * * @since 1.5 */ public class RelationService extends NotificationBroadcasterSupport implements RelationServiceMBean, MBeanRegistration, NotificationListener { // // Private members // // Map associating: // <relation id> -> <RelationSupport object/ObjectName> // depending if the relation has been created using createRelation() // method (so internally handled) or is an MBean added as a relation by the // user private Map<String,Object> myRelId2ObjMap = new HashMap<String,Object>(); // Map associating: // <relation id> -> <relation type name> private Map<String,String> myRelId2RelTypeMap = new HashMap<String,String>(); // Map associating: // <relation MBean Object Name> -> <relation id> private Map<ObjectName,String> myRelMBeanObjName2RelIdMap = new HashMap<ObjectName,String>(); // Map associating: // <relation type name> -> <RelationType object> private Map<String,RelationType> myRelType2ObjMap = new HashMap<String,RelationType>(); // Map associating: // <relation type name> -> ArrayList of <relation id> // to list all the relations of a given type private Map<String,List<String>> myRelType2RelIdsMap = new HashMap<String,List<String>>(); // Map associating: // <ObjectName> -> HashMap // the value HashMap mapping: // <relation id> -> ArrayList of <role name> // to track where a given MBean is referenced. private final Map<ObjectName,Map<String,List<String>>> myRefedMBeanObjName2RelIdsMap = new HashMap<ObjectName,Map<String,List<String>>>(); // Flag to indicate if, when a notification is received for the // unregistration of an MBean referenced in a relation, if an immediate // "purge" of the relations (look for the relations no // longer valid) has to be performed , or if that will be performed only // when the purgeRelations method will be explicitly called. // true is immediate purge. private boolean myPurgeFlag = true; // Internal counter to provide sequence numbers for notifications sent by: // - the Relation Service // - a relation handled by the Relation Service private final AtomicLong atomicSeqNo = new AtomicLong(); // ObjectName used to register the Relation Service in the MBean Server private ObjectName myObjName = null; // MBean Server where the Relation Service is registered private MBeanServer myMBeanServer = null; // Filter registered in the MBean Server with the Relation Service to be // informed of referenced MBean unregistrations private MBeanServerNotificationFilter myUnregNtfFilter = null; // List of unregistration notifications received (storage used if purge // of relations when unregistering a referenced MBean is not immediate but // on user request) private List<MBeanServerNotification> myUnregNtfList = new ArrayList<MBeanServerNotification>(); // // Constructor // /** * Constructor. * * @param immediatePurgeFlag flag to indicate when a notification is * received for the unregistration of an MBean referenced in a relation, if * an immediate "purge" of the relations (look for the relations no * longer valid) has to be performed , or if that will be performed only * when the purgeRelations method will be explicitly called. * <P>true is immediate purge. */ public RelationService(boolean immediatePurgeFlag) { RELATION_LOGGER.entering(RelationService.class.getName(), "RelationService"); setPurgeFlag(immediatePurgeFlag); RELATION_LOGGER.exiting(RelationService.class.getName(), "RelationService"); return; } /** * Checks if the Relation Service is active. * Current condition is that the Relation Service must be registered in the * MBean Server * * @exception RelationServiceNotRegisteredException if it is not * registered */ public void isActive() throws RelationServiceNotRegisteredException { if (myMBeanServer == null) { // MBean Server not set by preRegister(): relation service not // registered String excMsg = "Relation Service not registered in the MBean Server."; throw new RelationServiceNotRegisteredException(excMsg); } return; } // // MBeanRegistration interface // // Pre-registration: retrieves its ObjectName and MBean Server // // No exception thrown. public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { myMBeanServer = server; myObjName = name; return name; } // Post-registration: does nothing public void postRegister(Boolean registrationDone) { return; } // Pre-unregistration: does nothing public void preDeregister() throws Exception { return; } // Post-unregistration: does nothing public void postDeregister() { return; } // // Accessors // /** * Returns the flag to indicate if when a notification is received for the * unregistration of an MBean referenced in a relation, if an immediate * "purge" of the relations (look for the relations no longer valid) * has to be performed , or if that will be performed only when the * purgeRelations method will be explicitly called. * <P>true is immediate purge. * * @return true if purges are automatic. * * @see #setPurgeFlag */ public boolean getPurgeFlag() { return myPurgeFlag; } /** * Sets the flag to indicate if when a notification is received for the * unregistration of an MBean referenced in a relation, if an immediate * "purge" of the relations (look for the relations no longer valid) * has to be performed , or if that will be performed only when the * purgeRelations method will be explicitly called. * <P>true is immediate purge. * * @param purgeFlag flag * * @see #getPurgeFlag */ public void setPurgeFlag(boolean purgeFlag) { myPurgeFlag = purgeFlag; return; } // // Relation type handling // /** * Creates a relation type (a RelationTypeSupport object) with given * role infos (provided by the RoleInfo objects), and adds it in the * Relation Service. * * @param relationTypeName name of the relation type * @param roleInfoArray array of role infos * * @exception IllegalArgumentException if null parameter * @exception InvalidRelationTypeException If: * <P>- there is already a relation type with that name * <P>- the same name has been used for two different role infos * <P>- no role info provided * <P>- one null role info provided */ public void createRelationType(String relationTypeName, RoleInfo[] roleInfoArray) throws IllegalArgumentException, InvalidRelationTypeException { if (relationTypeName == null || roleInfoArray == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "createRelationType", relationTypeName); // Can throw an InvalidRelationTypeException RelationType relType = new RelationTypeSupport(relationTypeName, roleInfoArray); addRelationTypeInt(relType); RELATION_LOGGER.exiting(RelationService.class.getName(), "createRelationType"); return; } /** * Adds given object as a relation type. The object is expected to * implement the RelationType interface. * * @param relationTypeObj relation type object (implementing the * RelationType interface) * * @exception IllegalArgumentException if null parameter or if * {@link RelationType#getRelationTypeName * relationTypeObj.getRelationTypeName()} returns null. * @exception InvalidRelationTypeException if: * <P>- the same name has been used for two different roles * <P>- no role info provided * <P>- one null role info provided * <P>- there is already a relation type with that name */ public void addRelationType(RelationType relationTypeObj) throws IllegalArgumentException, InvalidRelationTypeException { if (relationTypeObj == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "addRelationType"); // Checks the role infos List<RoleInfo> roleInfoList = relationTypeObj.getRoleInfos(); if (roleInfoList == null) { String excMsg = "No role info provided."; throw new InvalidRelationTypeException(excMsg); } RoleInfo[] roleInfoArray = new RoleInfo[roleInfoList.size()]; int i = 0; for (RoleInfo currRoleInfo : roleInfoList) { roleInfoArray[i] = currRoleInfo; i++; } // Can throw InvalidRelationTypeException RelationTypeSupport.checkRoleInfos(roleInfoArray); addRelationTypeInt(relationTypeObj); RELATION_LOGGER.exiting(RelationService.class.getName(), "addRelationType"); return; } /** * Retrieves names of all known relation types. * * @return ArrayList of relation type names (Strings) */ public List<String> getAllRelationTypeNames() { ArrayList<String> result; synchronized(myRelType2ObjMap) { result = new ArrayList<String>(myRelType2ObjMap.keySet()); } return result; } /** * Retrieves list of role infos (RoleInfo objects) of a given relation * type. * * @param relationTypeName name of relation type * * @return ArrayList of RoleInfo. * * @exception IllegalArgumentException if null parameter * @exception RelationTypeNotFoundException if there is no relation type * with that name. */ public List<RoleInfo> getRoleInfos(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (relationTypeName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRoleInfos", relationTypeName); // Can throw a RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoleInfos"); return relType.getRoleInfos(); } /** * Retrieves role info for given role name of a given relation type. * * @param relationTypeName name of relation type * @param roleInfoName name of role * * @return RoleInfo object. * * @exception IllegalArgumentException if null parameter * @exception RelationTypeNotFoundException if the relation type is not * known in the Relation Service * @exception RoleInfoNotFoundException if the role is not part of the * relation type. */ public RoleInfo getRoleInfo(String relationTypeName, String roleInfoName) throws IllegalArgumentException, RelationTypeNotFoundException, RoleInfoNotFoundException { if (relationTypeName == null || roleInfoName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRoleInfo", new Object[] {relationTypeName, roleInfoName}); // Can throw a RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); // Can throw a RoleInfoNotFoundException RoleInfo roleInfo = relType.getRoleInfo(roleInfoName); RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoleInfo"); return roleInfo; } /** * Removes given relation type from Relation Service. * <P>The relation objects of that type will be removed from the * Relation Service. * * @param relationTypeName name of the relation type to be removed * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception IllegalArgumentException if null parameter * @exception RelationTypeNotFoundException If there is no relation type * with that name */ public void removeRelationType(String relationTypeName) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationTypeNotFoundException { // Can throw RelationServiceNotRegisteredException isActive(); if (relationTypeName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "removeRelationType", relationTypeName); // Checks if the relation type to be removed exists // Can throw a RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); // Retrieves the relation ids for relations of that type List<String> relIdList = null; synchronized(myRelType2RelIdsMap) { // Note: take a copy of the list as it is a part of a map that // will be updated by removeRelation() below. List<String> relIdList1 = myRelType2RelIdsMap.get(relationTypeName); if (relIdList1 != null) { relIdList = new ArrayList<String>(relIdList1); } } // Removes the relation type from all maps synchronized(myRelType2ObjMap) { myRelType2ObjMap.remove(relationTypeName); } synchronized(myRelType2RelIdsMap) { myRelType2RelIdsMap.remove(relationTypeName); } // Removes all relations of that type if (relIdList != null) { for (String currRelId : relIdList) { // Note: will remove it from myRelId2RelTypeMap :) // // Can throw RelationServiceNotRegisteredException (detected // above) // Shall not throw a RelationNotFoundException try { removeRelation(currRelId); } catch (RelationNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "removeRelationType"); return; } // // Relation handling // /** * Creates a simple relation (represented by a RelationSupport object) of * given relation type, and adds it in the Relation Service. * <P>Roles are initialized according to the role list provided in * parameter. The ones not initialized in this way are set to an empty * ArrayList of ObjectNames. * <P>A RelationNotification, with type RELATION_BASIC_CREATION, is sent. * * @param relationId relation identifier, to identify uniquely the relation * inside the Relation Service * @param relationTypeName name of the relation type (has to be created * in the Relation Service) * @param roleList role list to initialize roles of the relation (can * be null). * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception IllegalArgumentException if null parameter, except the role * list which can be null if no role initialization * @exception RoleNotFoundException if a value is provided for a role * that does not exist in the relation type * @exception InvalidRelationIdException if relation id already used * @exception RelationTypeNotFoundException if relation type not known in * Relation Service * @exception InvalidRoleValueException if: * <P>- the same role name is used for two different roles * <P>- the number of referenced MBeans in given value is less than * expected minimum degree * <P>- the number of referenced MBeans in provided value exceeds expected * maximum degree * <P>- one referenced MBean in the value is not an Object of the MBean * class expected for that role * <P>- an MBean provided for that role does not exist */ public void createRelation(String relationId, String relationTypeName, RoleList roleList) throws RelationServiceNotRegisteredException, IllegalArgumentException, RoleNotFoundException, InvalidRelationIdException, RelationTypeNotFoundException, InvalidRoleValueException { // Can throw RelationServiceNotRegisteredException isActive(); if (relationId == null || relationTypeName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "createRelation", new Object[] {relationId, relationTypeName, roleList}); // Creates RelationSupport object // Can throw InvalidRoleValueException RelationSupport relObj = new RelationSupport(relationId, myObjName, relationTypeName, roleList); // Adds relation object as a relation into the Relation Service // Can throw RoleNotFoundException, InvalidRelationId, // RelationTypeNotFoundException, InvalidRoleValueException // // Cannot throw MBeanException addRelationInt(true, relObj, null, relationId, relationTypeName, roleList); RELATION_LOGGER.exiting(RelationService.class.getName(), "createRelation"); return; } /** * Adds an MBean created by the user (and registered by him in the MBean * Server) as a relation in the Relation Service. * <P>To be added as a relation, the MBean must conform to the * following: * <P>- implement the Relation interface * <P>- have for RelationService ObjectName the ObjectName of current * Relation Service * <P>- have a relation id unique and unused in current Relation Service * <P>- have for relation type a relation type created in the Relation * Service * <P>- have roles conforming to the role info provided in the relation * type. * * @param relationObjectName ObjectName of the relation MBean to be added. * * @exception IllegalArgumentException if null parameter * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception NoSuchMethodException If the MBean does not implement the * Relation interface * @exception InvalidRelationIdException if: * <P>- no relation identifier in MBean * <P>- the relation identifier is already used in the Relation Service * @exception InstanceNotFoundException if the MBean for given ObjectName * has not been registered * @exception InvalidRelationServiceException if: * <P>- no Relation Service name in MBean * <P>- the Relation Service name in the MBean is not the one of the * current Relation Service * @exception RelationTypeNotFoundException if: * <P>- no relation type name in MBean * <P>- the relation type name in MBean does not correspond to a relation * type created in the Relation Service * @exception InvalidRoleValueException if: * <P>- the number of referenced MBeans in a role is less than * expected minimum degree * <P>- the number of referenced MBeans in a role exceeds expected * maximum degree * <P>- one referenced MBean in the value is not an Object of the MBean * class expected for that role * <P>- an MBean provided for a role does not exist * @exception RoleNotFoundException if a value is provided for a role * that does not exist in the relation type */ public void addRelation(ObjectName relationObjectName) throws IllegalArgumentException, RelationServiceNotRegisteredException, NoSuchMethodException, InvalidRelationIdException, InstanceNotFoundException, InvalidRelationServiceException, RelationTypeNotFoundException, RoleNotFoundException, InvalidRoleValueException { if (relationObjectName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "addRelation", relationObjectName); // Can throw RelationServiceNotRegisteredException isActive(); // Checks that the relation MBean implements the Relation interface. // It will also check that the provided ObjectName corresponds to a // registered MBean (else will throw an InstanceNotFoundException) if ((!(myMBeanServer.isInstanceOf(relationObjectName, "javax.management.relation.Relation")))) { String excMsg = "This MBean does not implement the Relation interface."; throw new NoSuchMethodException(excMsg); } // Checks there is a relation id in the relation MBean (its uniqueness // is checked in addRelationInt()) // Can throw InstanceNotFoundException (but detected above) // No MBeanException as no exception raised by this method, and no // ReflectionException String relId; try { relId = (String)(myMBeanServer.getAttribute(relationObjectName, "RelationId")); } catch (MBeanException exc1) { throw new RuntimeException( (exc1.getTargetException()).getMessage()); } catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (AttributeNotFoundException exc3) { throw new RuntimeException(exc3.getMessage()); } if (relId == null) { String excMsg = "This MBean does not provide a relation id."; throw new InvalidRelationIdException(excMsg); } // Checks that the Relation Service where the relation MBean is // expected to be added is the current one // Can throw InstanceNotFoundException (but detected above) // No MBeanException as no exception raised by this method, no // ReflectionException ObjectName relServObjName; try { relServObjName = (ObjectName) (myMBeanServer.getAttribute(relationObjectName, "RelationServiceName")); } catch (MBeanException exc1) { throw new RuntimeException( (exc1.getTargetException()).getMessage()); } catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (AttributeNotFoundException exc3) { throw new RuntimeException(exc3.getMessage()); } boolean badRelServFlag = false; if (relServObjName == null) { badRelServFlag = true; } else if (!(relServObjName.equals(myObjName))) { badRelServFlag = true; } if (badRelServFlag) { String excMsg = "The Relation Service referenced in the MBean is not the current one."; throw new InvalidRelationServiceException(excMsg); } // Checks that a relation type has been specified for the relation // Can throw InstanceNotFoundException (but detected above) // No MBeanException as no exception raised by this method, no // ReflectionException String relTypeName; try { relTypeName = (String)(myMBeanServer.getAttribute(relationObjectName, "RelationTypeName")); } catch (MBeanException exc1) { throw new RuntimeException( (exc1.getTargetException()).getMessage()); }catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (AttributeNotFoundException exc3) { throw new RuntimeException(exc3.getMessage()); } if (relTypeName == null) { String excMsg = "No relation type provided."; throw new RelationTypeNotFoundException(excMsg); } // Retrieves all roles without considering read mode // Can throw InstanceNotFoundException (but detected above) // No MBeanException as no exception raised by this method, no // ReflectionException RoleList roleList; try { roleList = (RoleList)(myMBeanServer.invoke(relationObjectName, "retrieveAllRoles", null, null)); } catch (MBeanException exc1) { throw new RuntimeException( (exc1.getTargetException()).getMessage()); } catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } // Can throw RoleNotFoundException, InvalidRelationIdException, // RelationTypeNotFoundException, InvalidRoleValueException addRelationInt(false, null, relationObjectName, relId, relTypeName, roleList); // Adds relation MBean ObjectName in map synchronized(myRelMBeanObjName2RelIdMap) { myRelMBeanObjName2RelIdMap.put(relationObjectName, relId); } // Updates flag to specify that the relation is managed by the Relation // Service // This flag and setter are inherited from RelationSupport and not parts // of the Relation interface, so may be not supported. try { myMBeanServer.setAttribute(relationObjectName, new Attribute( "RelationServiceManagementFlag", Boolean.TRUE)); } catch (Exception exc) { // OK : The flag is not supported. } // Updates listener information to received notification for // unregistration of this MBean List<ObjectName> newRefList = new ArrayList<ObjectName>(); newRefList.add(relationObjectName); updateUnregistrationListener(newRefList, null); RELATION_LOGGER.exiting(RelationService.class.getName(), "addRelation"); return; } /** * If the relation is represented by an MBean (created by the user and * added as a relation in the Relation Service), returns the ObjectName of * the MBean. * * @param relationId relation id identifying the relation * * @return ObjectName of the corresponding relation MBean, or null if * the relation is not an MBean. * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException there is no relation associated * to that id */ public ObjectName isRelationMBean(String relationId) throws IllegalArgumentException, RelationNotFoundException{ if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "isRelationMBean", relationId); // Can throw RelationNotFoundException Object result = getRelation(relationId); if (result instanceof ObjectName) { return ((ObjectName)result); } else { return null; } } /** * Returns the relation id associated to the given ObjectName if the * MBean has been added as a relation in the Relation Service. * * @param objectName ObjectName of supposed relation * * @return relation id (String) or null (if the ObjectName is not a * relation handled by the Relation Service) * * @exception IllegalArgumentException if null parameter */ public String isRelation(ObjectName objectName) throws IllegalArgumentException { if (objectName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "isRelation", objectName); String result = null; synchronized(myRelMBeanObjName2RelIdMap) { String relId = myRelMBeanObjName2RelIdMap.get(objectName); if (relId != null) { result = relId; } } return result; } /** * Checks if there is a relation identified in Relation Service with given * relation id. * * @param relationId relation id identifying the relation * * @return boolean: true if there is a relation, false else * * @exception IllegalArgumentException if null parameter */ public Boolean hasRelation(String relationId) throws IllegalArgumentException { if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "hasRelation", relationId); try { // Can throw RelationNotFoundException Object result = getRelation(relationId); return true; } catch (RelationNotFoundException exc) { return false; } } /** * Returns all the relation ids for all the relations handled by the * Relation Service. * * @return ArrayList of String */ public List<String> getAllRelationIds() { List<String> result; synchronized(myRelId2ObjMap) { result = new ArrayList<String>(myRelId2ObjMap.keySet()); } return result; } /** * Checks if given Role can be read in a relation of the given type. * * @param roleName name of role to be checked * @param relationTypeName name of the relation type * * @return an Integer wrapping an integer corresponding to possible * problems represented as constants in RoleUnresolved: * <P>- 0 if role can be read * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME * <P>- integer corresponding to RoleStatus.ROLE_NOT_READABLE * * @exception IllegalArgumentException if null parameter * @exception RelationTypeNotFoundException if the relation type is not * known in the Relation Service */ public Integer checkRoleReading(String roleName, String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (roleName == null || relationTypeName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "checkRoleReading", new Object[] {roleName, relationTypeName}); Integer result; // Can throw a RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); try { // Can throw a RoleInfoNotFoundException to be transformed into // returned value RoleStatus.NO_ROLE_WITH_NAME RoleInfo roleInfo = relType.getRoleInfo(roleName); result = checkRoleInt(1, roleName, null, roleInfo, false); } catch (RoleInfoNotFoundException exc) { result = Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME); } RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleReading"); return result; } /** * Checks if given Role can be set in a relation of given type. * * @param role role to be checked * @param relationTypeName name of relation type * @param initFlag flag to specify that the checking is done for the * initialization of a role, write access shall not be verified. * * @return an Integer wrapping an integer corresponding to possible * problems represented as constants in RoleUnresolved: * <P>- 0 if role can be set * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME * <P>- integer for RoleStatus.ROLE_NOT_WRITABLE * <P>- integer for RoleStatus.LESS_THAN_MIN_ROLE_DEGREE * <P>- integer for RoleStatus.MORE_THAN_MAX_ROLE_DEGREE * <P>- integer for RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS * <P>- integer for RoleStatus.REF_MBEAN_NOT_REGISTERED * * @exception IllegalArgumentException if null parameter * @exception RelationTypeNotFoundException if unknown relation type */ public Integer checkRoleWriting(Role role, String relationTypeName, Boolean initFlag) throws IllegalArgumentException, RelationTypeNotFoundException { if (role == null || relationTypeName == null || initFlag == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "checkRoleWriting", new Object[] {role, relationTypeName, initFlag}); // Can throw a RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); String roleName = role.getRoleName(); List<ObjectName> roleValue = role.getRoleValue(); boolean writeChkFlag = true; if (initFlag.booleanValue()) { writeChkFlag = false; } RoleInfo roleInfo; try { roleInfo = relType.getRoleInfo(roleName); } catch (RoleInfoNotFoundException exc) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleWriting"); return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME); } Integer result = checkRoleInt(2, roleName, roleValue, roleInfo, writeChkFlag); RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleWriting"); return result; } /** * Sends a notification (RelationNotification) for a relation creation. * The notification type is: * <P>- RelationNotification.RELATION_BASIC_CREATION if the relation is an * object internal to the Relation Service * <P>- RelationNotification.RELATION_MBEAN_CREATION if the relation is a * MBean added as a relation. * <P>The source object is the Relation Service itself. * <P>It is called in Relation Service createRelation() and * addRelation() methods. * * @param relationId relation identifier of the updated relation * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if there is no relation for given * relation id */ public void sendRelationCreationNotification(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "sendRelationCreationNotification", relationId); // Message StringBuilder ntfMsg = new StringBuilder("Creation of relation "); ntfMsg.append(relationId); // Can throw RelationNotFoundException sendNotificationInt(1, ntfMsg.toString(), relationId, null, null, null, null); RELATION_LOGGER.exiting(RelationService.class.getName(), "sendRelationCreationNotification"); return; } /** * Sends a notification (RelationNotification) for a role update in the * given relation. The notification type is: * <P>- RelationNotification.RELATION_BASIC_UPDATE if the relation is an * object internal to the Relation Service * <P>- RelationNotification.RELATION_MBEAN_UPDATE if the relation is a * MBean added as a relation. * <P>The source object is the Relation Service itself. * <P>It is called in relation MBean setRole() (for given role) and * setRoles() (for each role) methods (implementation provided in * RelationSupport class). * <P>It is also called in Relation Service setRole() (for given role) and * setRoles() (for each role) methods. * * @param relationId relation identifier of the updated relation * @param newRole new role (name and new value) * @param oldValue old role value (List of ObjectName objects) * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if there is no relation for given * relation id */ public void sendRoleUpdateNotification(String relationId, Role newRole, List<ObjectName> oldValue) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null || newRole == null || oldValue == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } if (!(oldValue instanceof ArrayList<?>)) oldValue = new ArrayList<ObjectName>(oldValue); RELATION_LOGGER.entering(RelationService.class.getName(), "sendRoleUpdateNotification", new Object[] {relationId, newRole, oldValue}); String roleName = newRole.getRoleName(); List<ObjectName> newRoleVal = newRole.getRoleValue(); // Message String newRoleValString = Role.roleValueToString(newRoleVal); String oldRoleValString = Role.roleValueToString(oldValue); StringBuilder ntfMsg = new StringBuilder("Value of role "); ntfMsg.append(roleName); ntfMsg.append(" has changed\nOld value:\n"); ntfMsg.append(oldRoleValString); ntfMsg.append("\nNew value:\n"); ntfMsg.append(newRoleValString); // Can throw a RelationNotFoundException sendNotificationInt(2, ntfMsg.toString(), relationId, null, roleName, newRoleVal, oldValue); RELATION_LOGGER.exiting(RelationService.class.getName(), "sendRoleUpdateNotification"); } /** * Sends a notification (RelationNotification) for a relation removal. * The notification type is: * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation is an * object internal to the Relation Service * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is a * MBean added as a relation. * <P>The source object is the Relation Service itself. * <P>It is called in Relation Service removeRelation() method. * * @param relationId relation identifier of the updated relation * @param unregMBeanList List of ObjectNames of MBeans expected * to be unregistered due to relation removal (can be null) * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if there is no relation for given * relation id */ public void sendRelationRemovalNotification(String relationId, List<ObjectName> unregMBeanList) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) { String excMsg = "Invalid parameter"; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "sendRelationRemovalNotification", new Object[] {relationId, unregMBeanList}); // Can throw RelationNotFoundException sendNotificationInt(3, "Removal of relation " + relationId, relationId, unregMBeanList, null, null, null); RELATION_LOGGER.exiting(RelationService.class.getName(), "sendRelationRemovalNotification"); return; } /** * Handles update of the Relation Service role map for the update of given * role in given relation. * <P>It is called in relation MBean setRole() (for given role) and * setRoles() (for each role) methods (implementation provided in * RelationSupport class). * <P>It is also called in Relation Service setRole() (for given role) and * setRoles() (for each role) methods. * <P>To allow the Relation Service to maintain the consistency (in case * of MBean unregistration) and to be able to perform queries, this method * must be called when a role is updated. * * @param relationId relation identifier of the updated relation * @param newRole new role (name and new value) * @param oldValue old role value (List of ObjectName objects) * * @exception IllegalArgumentException if null parameter * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception RelationNotFoundException if no relation for given id. */ public void updateRoleMap(String relationId, Role newRole, List<ObjectName> oldValue) throws IllegalArgumentException, RelationServiceNotRegisteredException, RelationNotFoundException { if (relationId == null || newRole == null || oldValue == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "updateRoleMap", new Object[] {relationId, newRole, oldValue}); // Can throw RelationServiceNotRegisteredException isActive(); // Verifies the relation has been added in the Relation Service // Can throw a RelationNotFoundException Object result = getRelation(relationId); String roleName = newRole.getRoleName(); List<ObjectName> newRoleValue = newRole.getRoleValue(); // Note: no need to test if oldValue not null before cloning, // tested above. List<ObjectName> oldRoleValue = new ArrayList<ObjectName>(oldValue); // List of ObjectNames of new referenced MBeans List<ObjectName> newRefList = new ArrayList<ObjectName>(); for (ObjectName currObjName : newRoleValue) { // Checks if this ObjectName was already present in old value // Note: use copy (oldRoleValue) instead of original // oldValue to speed up, as oldRoleValue is decreased // by removing unchanged references :) int currObjNamePos = oldRoleValue.indexOf(currObjName); if (currObjNamePos == -1) { // New reference to an ObjectName // Stores this reference into map // Returns true if new reference, false if MBean already // referenced boolean isNewFlag = addNewMBeanReference(currObjName, relationId, roleName); if (isNewFlag) { // Adds it into list of new reference newRefList.add(currObjName); } } else { // MBean was already referenced in old value // Removes it from old value (local list) to ignore it when // looking for remove MBean references oldRoleValue.remove(currObjNamePos); } } // List of ObjectNames of MBeans no longer referenced List<ObjectName> obsRefList = new ArrayList<ObjectName>(); // Each ObjectName remaining in oldRoleValue is an ObjectName no longer // referenced in new value for (ObjectName currObjName : oldRoleValue) { // Removes MBean reference from map // Returns true if the MBean is no longer referenced in any // relation boolean noLongerRefFlag = removeMBeanReference(currObjName, relationId, roleName, false); if (noLongerRefFlag) { // Adds it into list of references to be removed obsRefList.add(currObjName); } } // To avoid having one listener per ObjectName of referenced MBean, // and to increase performances, there is only one listener recording // all ObjectNames of interest updateUnregistrationListener(newRefList, obsRefList); RELATION_LOGGER.exiting(RelationService.class.getName(), "updateRoleMap"); return; } /** * Removes given relation from the Relation Service. * <P>A RelationNotification notification is sent, its type being: * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation was * only internal to the Relation Service * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is * registered as an MBean. * <P>For MBeans referenced in such relation, nothing will be done, * * @param relationId relation id of the relation to be removed * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation corresponding to * given relation id */ public void removeRelation(String relationId) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationNotFoundException { // Can throw RelationServiceNotRegisteredException isActive(); if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "removeRelation", relationId); // Checks there is a relation with this id // Can throw RelationNotFoundException Object result = getRelation(relationId); // Removes it from listener filter if (result instanceof ObjectName) { List<ObjectName> obsRefList = new ArrayList<ObjectName>(); obsRefList.add((ObjectName)result); // Can throw a RelationServiceNotRegisteredException updateUnregistrationListener(null, obsRefList); } // Sends a notification // Note: has to be done FIRST as needs the relation to be still in the // Relation Service // No RelationNotFoundException as checked above // Revisit [cebro] Handle CIM "Delete" and "IfDeleted" qualifiers: // deleting the relation can mean to delete referenced MBeans. In // that case, MBeans to be unregistered are put in a list sent along // with the notification below // Can throw a RelationNotFoundException (but detected above) sendRelationRemovalNotification(relationId, null); // Removes the relation from various internal maps // - MBean reference map // Retrieves the MBeans referenced in this relation // Note: here we cannot use removeMBeanReference() because it would // require to know the MBeans referenced in the relation. For // that it would be necessary to call 'getReferencedMBeans()' // on the relation itself. Ok if it is an internal one, but if // it is an MBean, it is possible it is already unregistered, so // not available through the MBean Server. List<ObjectName> refMBeanList = new ArrayList<ObjectName>(); // List of MBeans no longer referenced in any relation, to be // removed fom the map List<ObjectName> nonRefObjNameList = new ArrayList<ObjectName>(); synchronized(myRefedMBeanObjName2RelIdsMap) { for (ObjectName currRefObjName : myRefedMBeanObjName2RelIdsMap.keySet()) { // Retrieves relations where the MBean is referenced Map<String,List<String>> relIdMap = myRefedMBeanObjName2RelIdsMap.get(currRefObjName); if (relIdMap.containsKey(relationId)) { relIdMap.remove(relationId); refMBeanList.add(currRefObjName); } if (relIdMap.isEmpty()) { // MBean no longer referenced // Note: do not remove it here because pointed by the // iterator! nonRefObjNameList.add(currRefObjName); } } // Cleans MBean reference map by removing MBeans no longer // referenced for (ObjectName currRefObjName : nonRefObjNameList) { myRefedMBeanObjName2RelIdsMap.remove(currRefObjName); } } // - Relation id to object map synchronized(myRelId2ObjMap) { myRelId2ObjMap.remove(relationId); } if (result instanceof ObjectName) { // - ObjectName to relation id map synchronized(myRelMBeanObjName2RelIdMap) { myRelMBeanObjName2RelIdMap.remove((ObjectName)result); } } // Relation id to relation type name map // First retrieves the relation type name String relTypeName; synchronized(myRelId2RelTypeMap) { relTypeName = myRelId2RelTypeMap.get(relationId); myRelId2RelTypeMap.remove(relationId); } // - Relation type name to relation id map synchronized(myRelType2RelIdsMap) { List<String> relIdList = myRelType2RelIdsMap.get(relTypeName); if (relIdList != null) { // Can be null if called from removeRelationType() relIdList.remove(relationId); if (relIdList.isEmpty()) { // No other relation of that type myRelType2RelIdsMap.remove(relTypeName); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "removeRelation"); return; } /** * Purges the relations. * * <P>Depending on the purgeFlag value, this method is either called * automatically when a notification is received for the unregistration of * an MBean referenced in a relation (if the flag is set to true), or not * (if the flag is set to false). * <P>In that case it is up to the user to call it to maintain the * consistency of the relations. To be kept in mind that if an MBean is * unregistered and the purge not done immediately, if the ObjectName is * reused and assigned to another MBean referenced in a relation, calling * manually this purgeRelations() method will cause trouble, as will * consider the ObjectName as corresponding to the unregistered MBean, not * seeing the new one. * * <P>The behavior depends on the cardinality of the role where the * unregistered MBean is referenced: * <P>- if removing one MBean reference in the role makes its number of * references less than the minimum degree, the relation has to be removed. * <P>- if the remaining number of references after removing the MBean * reference is still in the cardinality range, keep the relation and * update it calling its handleMBeanUnregistration() callback. * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server. */ public void purgeRelations() throws RelationServiceNotRegisteredException { RELATION_LOGGER.entering(RelationService.class.getName(), "purgeRelations"); // Can throw RelationServiceNotRegisteredException isActive(); // Revisit [cebro] Handle the CIM "Delete" and "IfDeleted" qualifier: // if the unregistered MBean has the "IfDeleted" qualifier, // possible that the relation itself or other referenced MBeans // have to be removed (then a notification would have to be sent // to inform that they should be unregistered. // Clones the list of notifications to be able to still receive new // notifications while proceeding those ones List<MBeanServerNotification> localUnregNtfList; synchronized(myRefedMBeanObjName2RelIdsMap) { localUnregNtfList = new ArrayList<MBeanServerNotification>(myUnregNtfList); // Resets list myUnregNtfList = new ArrayList<MBeanServerNotification>(); } // Updates the listener filter to avoid receiving notifications for // those MBeans again // Makes also a local "myRefedMBeanObjName2RelIdsMap" map, mapping // ObjectName -> relId -> roles, to remove the MBean from the global // map // List of references to be removed from the listener filter List<ObjectName> obsRefList = new ArrayList<ObjectName>(); // Map including ObjectNames for unregistered MBeans, with // referencing relation ids and roles Map<ObjectName,Map<String,List<String>>> localMBean2RelIdMap = new HashMap<ObjectName,Map<String,List<String>>>(); synchronized(myRefedMBeanObjName2RelIdsMap) { for (MBeanServerNotification currNtf : localUnregNtfList) { ObjectName unregMBeanName = currNtf.getMBeanName(); // Adds the unregsitered MBean in the list of references to // remove from the listener filter obsRefList.add(unregMBeanName); // Retrieves the associated map of relation ids and roles Map<String,List<String>> relIdMap = myRefedMBeanObjName2RelIdsMap.get(unregMBeanName); localMBean2RelIdMap.put(unregMBeanName, relIdMap); myRefedMBeanObjName2RelIdsMap.remove(unregMBeanName); } } // Updates the listener // Can throw RelationServiceNotRegisteredException updateUnregistrationListener(null, obsRefList); for (MBeanServerNotification currNtf : localUnregNtfList) { ObjectName unregMBeanName = currNtf.getMBeanName(); // Retrieves the relations where the MBean is referenced Map<String,List<String>> localRelIdMap = localMBean2RelIdMap.get(unregMBeanName); // List of relation ids where the unregistered MBean is // referenced for (Map.Entry<String,List<String>> currRel : localRelIdMap.entrySet()) { final String currRelId = currRel.getKey(); // List of roles of the relation where the MBean is // referenced List<String> localRoleNameList = currRel.getValue(); // Checks if the relation has to be removed or not, // regarding expected minimum role cardinality and current // number of references after removal of the current one // If the relation is kept, calls // handleMBeanUnregistration() callback of the relation to // update it // // Can throw RelationServiceNotRegisteredException // // Shall not throw RelationNotFoundException, // RoleNotFoundException, MBeanException try { handleReferenceUnregistration(currRelId, unregMBeanName, localRoleNameList); } catch (RelationNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (RoleNotFoundException exc2) { throw new RuntimeException(exc2.getMessage()); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "purgeRelations"); return; } /** * Retrieves the relations where a given MBean is referenced. * <P>This corresponds to the CIM "References" and "ReferenceNames" * operations. * * @param mbeanName ObjectName of MBean * @param relationTypeName can be null; if specified, only the relations * of that type will be considered in the search. Else all relation types * are considered. * @param roleName can be null; if specified, only the relations * where the MBean is referenced in that role will be returned. Else all * roles are considered. * * @return an HashMap, where the keys are the relation ids of the relations * where the MBean is referenced, and the value is, for each key, * an ArrayList of role names (as an MBean can be referenced in several * roles in the same relation). * * @exception IllegalArgumentException if null parameter */ public Map<String,List<String>> findReferencingRelations(ObjectName mbeanName, String relationTypeName, String roleName) throws IllegalArgumentException { if (mbeanName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "findReferencingRelations", new Object[] {mbeanName, relationTypeName, roleName}); Map<String,List<String>> result = new HashMap<String,List<String>>(); synchronized(myRefedMBeanObjName2RelIdsMap) { // Retrieves the relations referencing the MBean Map<String,List<String>> relId2RoleNamesMap = myRefedMBeanObjName2RelIdsMap.get(mbeanName); if (relId2RoleNamesMap != null) { // Relation Ids where the MBean is referenced Set<String> allRelIdSet = relId2RoleNamesMap.keySet(); // List of relation ids of interest regarding the selected // relation type List<String> relIdList; if (relationTypeName == null) { // Considers all relations relIdList = new ArrayList<String>(allRelIdSet); } else { relIdList = new ArrayList<String>(); // Considers only the relation ids for relations of given // type for (String currRelId : allRelIdSet) { // Retrieves its relation type String currRelTypeName; synchronized(myRelId2RelTypeMap) { currRelTypeName = myRelId2RelTypeMap.get(currRelId); } if (currRelTypeName.equals(relationTypeName)) { relIdList.add(currRelId); } } } // Now looks at the roles where the MBean is expected to be // referenced for (String currRelId : relIdList) { // Retrieves list of role names where the MBean is // referenced List<String> currRoleNameList = relId2RoleNamesMap.get(currRelId); if (roleName == null) { // All roles to be considered // Note: no need to test if list not null before // cloning, MUST be not null else bug :( result.put(currRelId, new ArrayList<String>(currRoleNameList)); } else if (currRoleNameList.contains(roleName)) { // Filters only the relations where the MBean is // referenced in // given role List<String> dummyList = new ArrayList<String>(); dummyList.add(roleName); result.put(currRelId, dummyList); } } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "findReferencingRelations"); return result; } /** * Retrieves the MBeans associated to given one in a relation. * <P>This corresponds to CIM Associators and AssociatorNames operations. * * @param mbeanName ObjectName of MBean * @param relationTypeName can be null; if specified, only the relations * of that type will be considered in the search. Else all * relation types are considered. * @param roleName can be null; if specified, only the relations * where the MBean is referenced in that role will be considered. Else all * roles are considered. * * @return an HashMap, where the keys are the ObjectNames of the MBeans * associated to given MBean, and the value is, for each key, an ArrayList * of the relation ids of the relations where the key MBean is * associated to given one (as they can be associated in several different * relations). * * @exception IllegalArgumentException if null parameter */ public Map<ObjectName,List<String>> findAssociatedMBeans(ObjectName mbeanName, String relationTypeName, String roleName) throws IllegalArgumentException { if (mbeanName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "findAssociatedMBeans", new Object[] {mbeanName, relationTypeName, roleName}); // Retrieves the map <relation id> -> <role names> for those // criterias Map<String,List<String>> relId2RoleNamesMap = findReferencingRelations(mbeanName, relationTypeName, roleName); Map<ObjectName,List<String>> result = new HashMap<ObjectName,List<String>>(); for (String currRelId : relId2RoleNamesMap.keySet()) { // Retrieves ObjectNames of MBeans referenced in this relation // // Shall not throw a RelationNotFoundException if incorrect status // of maps :( Map<ObjectName,List<String>> objName2RoleNamesMap; try { objName2RoleNamesMap = getReferencedMBeans(currRelId); } catch (RelationNotFoundException exc) { throw new RuntimeException(exc.getMessage()); } // For each MBean associated to given one in a relation, adds the // association <ObjectName> -> <relation id> into result map for (ObjectName currObjName : objName2RoleNamesMap.keySet()) { if (!(currObjName.equals(mbeanName))) { // Sees if this MBean is already associated to the given // one in another relation List<String> currRelIdList = result.get(currObjName); if (currRelIdList == null) { currRelIdList = new ArrayList<String>(); currRelIdList.add(currRelId); result.put(currObjName, currRelIdList); } else { currRelIdList.add(currRelId); } } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "findAssociatedMBeans"); return result; } /** * Returns the relation ids for relations of the given type. * * @param relationTypeName relation type name * * @return an ArrayList of relation ids. * * @exception IllegalArgumentException if null parameter * @exception RelationTypeNotFoundException if there is no relation type * with that name. */ public List<String> findRelationsOfType(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (relationTypeName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "findRelationsOfType"); // Can throw RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); List<String> result; synchronized(myRelType2RelIdsMap) { List<String> result1 = myRelType2RelIdsMap.get(relationTypeName); if (result1 == null) result = new ArrayList<String>(); else result = new ArrayList<String>(result1); } RELATION_LOGGER.exiting(RelationService.class.getName(), "findRelationsOfType"); return result; } /** * Retrieves role value for given role name in given relation. * * @param relationId relation id * @param roleName name of role * * @return the ArrayList of ObjectName objects being the role value * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation with given id * @exception RoleNotFoundException if: * <P>- there is no role with given name * <P>or * <P>- the role is not readable. * * @see #setRole */ public List<ObjectName> getRole(String relationId, String roleName) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationNotFoundException, RoleNotFoundException { if (relationId == null || roleName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRole", new Object[] {relationId, roleName}); // Can throw RelationServiceNotRegisteredException isActive(); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); List<ObjectName> result; if (relObj instanceof RelationSupport) { // Internal relation // Can throw RoleNotFoundException result = cast( ((RelationSupport)relObj).getRoleInt(roleName, true, this, false)); } else { // Relation MBean Object[] params = new Object[1]; params[0] = roleName; String[] signature = new String[1]; signature[0] = "java.lang.String"; // Can throw MBeanException wrapping a RoleNotFoundException: // throw wrapped exception // // Shall not throw InstanceNotFoundException or ReflectionException try { List<ObjectName> invokeResult = cast( myMBeanServer.invoke(((ObjectName)relObj), "getRole", params, signature)); if (invokeResult == null || invokeResult instanceof ArrayList<?>) result = invokeResult; else result = new ArrayList<ObjectName>(invokeResult); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (MBeanException exc3) { Exception wrappedExc = exc3.getTargetException(); if (wrappedExc instanceof RoleNotFoundException) { throw ((RoleNotFoundException)wrappedExc); } else { throw new RuntimeException(wrappedExc.getMessage()); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRole"); return result; } /** * Retrieves values of roles with given names in given relation. * * @param relationId relation id * @param roleNameArray array of names of roles to be retrieved * * @return a RoleResult object, including a RoleList (for roles * successfully retrieved) and a RoleUnresolvedList (for roles not * retrieved). * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation with given id * * @see #setRoles */ public RoleResult getRoles(String relationId, String[] roleNameArray) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationNotFoundException { if (relationId == null || roleNameArray == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRoles", relationId); // Can throw RelationServiceNotRegisteredException isActive(); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); RoleResult result; if (relObj instanceof RelationSupport) { // Internal relation result = ((RelationSupport)relObj).getRolesInt(roleNameArray, true, this); } else { // Relation MBean Object[] params = new Object[1]; params[0] = roleNameArray; String[] signature = new String[1]; try { signature[0] = (roleNameArray.getClass()).getName(); } catch (Exception exc) { // OK : This is an array of java.lang.String // so this should never happen... } // Shall not throw InstanceNotFoundException, ReflectionException // or MBeanException try { result = (RoleResult) (myMBeanServer.invoke(((ObjectName)relObj), "getRoles", params, signature)); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (MBeanException exc3) { throw new RuntimeException((exc3.getTargetException()).getMessage()); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoles"); return result; } /** * Returns all roles present in the relation. * * @param relationId relation id * * @return a RoleResult object, including a RoleList (for roles * successfully retrieved) and a RoleUnresolvedList (for roles not * readable). * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation for given id * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server */ public RoleResult getAllRoles(String relationId) throws IllegalArgumentException, RelationNotFoundException, RelationServiceNotRegisteredException { if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRoles", relationId); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); RoleResult result; if (relObj instanceof RelationSupport) { // Internal relation result = ((RelationSupport)relObj).getAllRolesInt(true, this); } else { // Relation MBean // Shall not throw any Exception try { result = (RoleResult) (myMBeanServer.getAttribute(((ObjectName)relObj), "AllRoles")); } catch (Exception exc) { throw new RuntimeException(exc.getMessage()); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoles"); return result; } /** * Retrieves the number of MBeans currently referenced in the given role. * * @param relationId relation id * @param roleName name of role * * @return the number of currently referenced MBeans in that role * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation with given id * @exception RoleNotFoundException if there is no role with given name */ public Integer getRoleCardinality(String relationId, String roleName) throws IllegalArgumentException, RelationNotFoundException, RoleNotFoundException { if (relationId == null || roleName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRoleCardinality", new Object[] {relationId, roleName}); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); Integer result; if (relObj instanceof RelationSupport) { // Internal relation // Can throw RoleNotFoundException result = ((RelationSupport)relObj).getRoleCardinality(roleName); } else { // Relation MBean Object[] params = new Object[1]; params[0] = roleName; String[] signature = new String[1]; signature[0] = "java.lang.String"; // Can throw MBeanException wrapping RoleNotFoundException: // throw wrapped exception // // Shall not throw InstanceNotFoundException or ReflectionException try { result = (Integer) (myMBeanServer.invoke(((ObjectName)relObj), "getRoleCardinality", params, signature)); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (MBeanException exc3) { Exception wrappedExc = exc3.getTargetException(); if (wrappedExc instanceof RoleNotFoundException) { throw ((RoleNotFoundException)wrappedExc); } else { throw new RuntimeException(wrappedExc.getMessage()); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoleCardinality"); return result; } /** * Sets the given role in given relation. * <P>Will check the role according to its corresponding role definition * provided in relation's relation type * <P>The Relation Service will keep track of the change to keep the * consistency of relations by handling referenced MBean unregistrations. * * @param relationId relation id * @param role role to be set (name and new value) * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation with given id * @exception RoleNotFoundException if the role does not exist or is not * writable * @exception InvalidRoleValueException if value provided for role is not * valid: * <P>- the number of referenced MBeans in given value is less than * expected minimum degree * <P>or * <P>- the number of referenced MBeans in provided value exceeds expected * maximum degree * <P>or * <P>- one referenced MBean in the value is not an Object of the MBean * class expected for that role * <P>or * <P>- an MBean provided for that role does not exist * * @see #getRole */ public void setRole(String relationId, Role role) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationNotFoundException, RoleNotFoundException, InvalidRoleValueException { if (relationId == null || role == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "setRole", new Object[] {relationId, role}); // Can throw RelationServiceNotRegisteredException isActive(); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); if (relObj instanceof RelationSupport) { // Internal relation // Can throw RoleNotFoundException, // InvalidRoleValueException and // RelationServiceNotRegisteredException // // Shall not throw RelationTypeNotFoundException // (as relation exists in the RS, its relation type is known) try { ((RelationSupport)relObj).setRoleInt(role, true, this, false); } catch (RelationTypeNotFoundException exc) { throw new RuntimeException(exc.getMessage()); } } else { // Relation MBean Object[] params = new Object[1]; params[0] = role; String[] signature = new String[1]; signature[0] = "javax.management.relation.Role"; // Can throw MBeanException wrapping RoleNotFoundException, // InvalidRoleValueException // // Shall not MBeanException wrapping an MBeanException wrapping // RelationTypeNotFoundException, or ReflectionException, or // InstanceNotFoundException try { myMBeanServer.setAttribute(((ObjectName)relObj), new Attribute("Role", role)); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc3) { throw new RuntimeException(exc3.getMessage()); } catch (MBeanException exc2) { Exception wrappedExc = exc2.getTargetException(); if (wrappedExc instanceof RoleNotFoundException) { throw ((RoleNotFoundException)wrappedExc); } else if (wrappedExc instanceof InvalidRoleValueException) { throw ((InvalidRoleValueException)wrappedExc); } else { throw new RuntimeException(wrappedExc.getMessage()); } } catch (AttributeNotFoundException exc4) { throw new RuntimeException(exc4.getMessage()); } catch (InvalidAttributeValueException exc5) { throw new RuntimeException(exc5.getMessage()); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "setRole"); return; } /** * Sets the given roles in given relation. * <P>Will check the role according to its corresponding role definition * provided in relation's relation type * <P>The Relation Service keeps track of the changes to keep the * consistency of relations by handling referenced MBean unregistrations. * * @param relationId relation id * @param roleList list of roles to be set * * @return a RoleResult object, including a RoleList (for roles * successfully set) and a RoleUnresolvedList (for roles not * set). * * @exception RelationServiceNotRegisteredException if the Relation * Service is not registered in the MBean Server * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation with given id * * @see #getRoles */ public RoleResult setRoles(String relationId, RoleList roleList) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationNotFoundException { if (relationId == null || roleList == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "setRoles", new Object[] {relationId, roleList}); // Can throw RelationServiceNotRegisteredException isActive(); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); RoleResult result; if (relObj instanceof RelationSupport) { // Internal relation // Can throw RelationServiceNotRegisteredException // // Shall not throw RelationTypeNotFoundException (as relation is // known, its relation type exists) try { result = ((RelationSupport)relObj).setRolesInt(roleList, true, this); } catch (RelationTypeNotFoundException exc) { throw new RuntimeException(exc.getMessage()); } } else { // Relation MBean Object[] params = new Object[1]; params[0] = roleList; String[] signature = new String[1]; signature[0] = "javax.management.relation.RoleList"; // Shall not throw InstanceNotFoundException or an MBeanException // or ReflectionException try { result = (RoleResult) (myMBeanServer.invoke(((ObjectName)relObj), "setRoles", params, signature)); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc3) { throw new RuntimeException(exc3.getMessage()); } catch (MBeanException exc2) { throw new RuntimeException((exc2.getTargetException()).getMessage()); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "setRoles"); return result; } /** * Retrieves MBeans referenced in the various roles of the relation. * * @param relationId relation id * * @return a HashMap mapping: * <P> ObjectName -> ArrayList of String (role * names) * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation for given * relation id */ public Map<ObjectName,List<String>> getReferencedMBeans(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getReferencedMBeans", relationId); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); Map<ObjectName,List<String>> result; if (relObj instanceof RelationSupport) { // Internal relation result = ((RelationSupport)relObj).getReferencedMBeans(); } else { // Relation MBean // No Exception try { result = cast( myMBeanServer.getAttribute(((ObjectName)relObj), "ReferencedMBeans")); } catch (Exception exc) { throw new RuntimeException(exc.getMessage()); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "getReferencedMBeans"); return result; } /** * Returns name of associated relation type for given relation. * * @param relationId relation id * * @return the name of the associated relation type. * * @exception IllegalArgumentException if null parameter * @exception RelationNotFoundException if no relation for given * relation id */ public String getRelationTypeName(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRelationTypeName", relationId); // Can throw a RelationNotFoundException Object relObj = getRelation(relationId); String result; if (relObj instanceof RelationSupport) { // Internal relation result = ((RelationSupport)relObj).getRelationTypeName(); } else { // Relation MBean // No Exception try { result = (String) (myMBeanServer.getAttribute(((ObjectName)relObj), "RelationTypeName")); } catch (Exception exc) { throw new RuntimeException(exc.getMessage()); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRelationTypeName"); return result; } // // NotificationListener Interface // /** * Invoked when a JMX notification occurs. * Currently handles notifications for unregistration of MBeans, either * referenced in a relation role or being a relation itself. * * @param notif The notification. * @param handback An opaque object which helps the listener to * associate information regarding the MBean emitter (can be null). */ public void handleNotification(Notification notif, Object handback) { if (notif == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "handleNotification", notif); if (notif instanceof MBeanServerNotification) { MBeanServerNotification mbsNtf = (MBeanServerNotification) notif; String ntfType = notif.getType(); if (ntfType.equals( MBeanServerNotification.UNREGISTRATION_NOTIFICATION )) { ObjectName mbeanName = ((MBeanServerNotification)notif).getMBeanName(); // Note: use a flag to block access to // myRefedMBeanObjName2RelIdsMap only for a quick access boolean isRefedMBeanFlag = false; synchronized(myRefedMBeanObjName2RelIdsMap) { if (myRefedMBeanObjName2RelIdsMap.containsKey(mbeanName)) { // Unregistration of a referenced MBean synchronized(myUnregNtfList) { myUnregNtfList.add(mbsNtf); } isRefedMBeanFlag = true; } if (isRefedMBeanFlag && myPurgeFlag) { // Immediate purge // Can throw RelationServiceNotRegisteredException // but assume that will be fine :) try { purgeRelations(); } catch (Exception exc) { throw new RuntimeException(exc.getMessage()); } } } // Note: do both tests as a relation can be an MBean and be // itself referenced in another relation :) String relId; synchronized(myRelMBeanObjName2RelIdMap){ relId = myRelMBeanObjName2RelIdMap.get(mbeanName); } if (relId != null) { // Unregistration of a relation MBean // Can throw RelationTypeNotFoundException, // RelationServiceNotRegisteredException // // Shall not throw RelationTypeNotFoundException or // InstanceNotFoundException try { removeRelation(relId); } catch (Exception exc) { throw new RuntimeException(exc.getMessage()); } } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "handleNotification"); return; } // // NotificationBroadcaster interface // /** * Returns a NotificationInfo object containing the name of the Java class * of the notification and the notification types sent. */ public MBeanNotificationInfo[] getNotificationInfo() { RELATION_LOGGER.entering(RelationService.class.getName(), "getNotificationInfo"); String ntfClass = "javax.management.relation.RelationNotification"; String[] ntfTypes = new String[] { RelationNotification.RELATION_BASIC_CREATION, RelationNotification.RELATION_MBEAN_CREATION, RelationNotification.RELATION_BASIC_UPDATE, RelationNotification.RELATION_MBEAN_UPDATE, RelationNotification.RELATION_BASIC_REMOVAL, RelationNotification.RELATION_MBEAN_REMOVAL, }; String ntfDesc = "Sent when a relation is created, updated or deleted."; MBeanNotificationInfo ntfInfo = new MBeanNotificationInfo(ntfTypes, ntfClass, ntfDesc); RELATION_LOGGER.exiting(RelationService.class.getName(), "getNotificationInfo"); return new MBeanNotificationInfo[] {ntfInfo}; } // // Misc // // Adds given object as a relation type. // // -param relationTypeObj relation type object // // -exception IllegalArgumentException if null parameter // -exception InvalidRelationTypeException if there is already a relation // type with that name private void addRelationTypeInt(RelationType relationTypeObj) throws IllegalArgumentException, InvalidRelationTypeException { if (relationTypeObj == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "addRelationTypeInt"); String relTypeName = relationTypeObj.getRelationTypeName(); // Checks that there is not already a relation type with that name // existing in the Relation Service try { // Can throw a RelationTypeNotFoundException (in fact should ;) RelationType relType = getRelationType(relTypeName); if (relType != null) { String excMsg = "There is already a relation type in the Relation Service with name "; StringBuilder excMsgStrB = new StringBuilder(excMsg); excMsgStrB.append(relTypeName); throw new InvalidRelationTypeException(excMsgStrB.toString()); } } catch (RelationTypeNotFoundException exc) { // OK : The RelationType could not be found. } // Adds the relation type synchronized(myRelType2ObjMap) { myRelType2ObjMap.put(relTypeName, relationTypeObj); } if (relationTypeObj instanceof RelationTypeSupport) { ((RelationTypeSupport)relationTypeObj).setRelationServiceFlag(true); } RELATION_LOGGER.exiting(RelationService.class.getName(), "addRelationTypeInt"); return; } // Retrieves relation type with given name // // -param relationTypeName expected name of a relation type created in the // Relation Service // // -return RelationType object corresponding to given name // // -exception IllegalArgumentException if null parameter // -exception RelationTypeNotFoundException if no relation type for that // name created in Relation Service // RelationType getRelationType(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (relationTypeName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRelationType", relationTypeName); // No null relation type accepted, so can use get() RelationType relType; synchronized(myRelType2ObjMap) { relType = (myRelType2ObjMap.get(relationTypeName)); } if (relType == null) { String excMsg = "No relation type created in the Relation Service with the name "; StringBuilder excMsgStrB = new StringBuilder(excMsg); excMsgStrB.append(relationTypeName); throw new RelationTypeNotFoundException(excMsgStrB.toString()); } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRelationType"); return relType; } // Retrieves relation corresponding to given relation id. // Returns either: // - a RelationSupport object if the relation is internal // or // - the ObjectName of the corresponding MBean // // -param relationId expected relation id // // -return RelationSupport object or ObjectName of relation with given id // // -exception IllegalArgumentException if null parameter // -exception RelationNotFoundException if no relation for that // relation id created in Relation Service // Object getRelation(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "getRelation", relationId); // No null relation accepted, so can use get() Object rel; synchronized(myRelId2ObjMap) { rel = myRelId2ObjMap.get(relationId); } if (rel == null) { String excMsg = "No relation associated to relation id " + relationId; throw new RelationNotFoundException(excMsg); } RELATION_LOGGER.exiting(RelationService.class.getName(), "getRelation"); return rel; } // Adds a new MBean reference (reference to an ObjectName) in the // referenced MBean map (myRefedMBeanObjName2RelIdsMap). // // -param objectName ObjectName of new referenced MBean // -param relationId relation id of the relation where the MBean is // referenced // -param roleName name of the role where the MBean is referenced // // -return boolean: // - true if the MBean was not referenced before, so really a new // reference // - false else // // -exception IllegalArgumentException if null parameter private boolean addNewMBeanReference(ObjectName objectName, String relationId, String roleName) throws IllegalArgumentException { if (objectName == null || relationId == null || roleName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "addNewMBeanReference", new Object[] {objectName, relationId, roleName}); boolean isNewFlag = false; synchronized(myRefedMBeanObjName2RelIdsMap) { // Checks if the MBean was already referenced // No null value allowed, use get() directly Map<String,List<String>> mbeanRefMap = myRefedMBeanObjName2RelIdsMap.get(objectName); if (mbeanRefMap == null) { // MBean not referenced in any relation yet isNewFlag = true; // List of roles where the MBean is referenced in given // relation List<String> roleNames = new ArrayList<String>(); roleNames.add(roleName); // Map of relations where the MBean is referenced mbeanRefMap = new HashMap<String,List<String>>(); mbeanRefMap.put(relationId, roleNames); myRefedMBeanObjName2RelIdsMap.put(objectName, mbeanRefMap); } else { // MBean already referenced in at least another relation // Checks if already referenced in another role in current // relation List<String> roleNames = mbeanRefMap.get(relationId); if (roleNames == null) { // MBean not referenced in current relation // List of roles where the MBean is referenced in given // relation roleNames = new ArrayList<String>(); roleNames.add(roleName); // Adds new reference done in current relation mbeanRefMap.put(relationId, roleNames); } else { // MBean already referenced in current relation in another // role // Adds new reference done roleNames.add(roleName); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "addNewMBeanReference"); return isNewFlag; } // Removes an obsolete MBean reference (reference to an ObjectName) in // the referenced MBean map (myRefedMBeanObjName2RelIdsMap). // // -param objectName ObjectName of MBean no longer referenced // -param relationId relation id of the relation where the MBean was // referenced // -param roleName name of the role where the MBean was referenced // -param allRolesFlag flag, if true removes reference to MBean for all // roles in the relation, not only for the one above // // -return boolean: // - true if the MBean is no longer reference in any relation // - false else // // -exception IllegalArgumentException if null parameter private boolean removeMBeanReference(ObjectName objectName, String relationId, String roleName, boolean allRolesFlag) throws IllegalArgumentException { if (objectName == null || relationId == null || roleName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "removeMBeanReference", new Object[] {objectName, relationId, roleName, allRolesFlag}); boolean noLongerRefFlag = false; synchronized(myRefedMBeanObjName2RelIdsMap) { // Retrieves the set of relations (designed via their relation ids) // where the MBean is referenced // Note that it is possible that the MBean has already been removed // from the internal map: this is the case when the MBean is // unregistered, the role is updated, then we arrive here. Map<String,List<String>> mbeanRefMap = (myRefedMBeanObjName2RelIdsMap.get(objectName)); if (mbeanRefMap == null) { // The MBean is no longer referenced RELATION_LOGGER.exiting(RelationService.class.getName(), "removeMBeanReference"); return true; } List<String> roleNames = null; if (!allRolesFlag) { // Now retrieves the roles of current relation where the MBean // was referenced roleNames = mbeanRefMap.get(relationId); // Removes obsolete reference to role int obsRefIdx = roleNames.indexOf(roleName); if (obsRefIdx != -1) { roleNames.remove(obsRefIdx); } } // Checks if there is still at least one role in current relation // where the MBean is referenced if (roleNames.isEmpty() || allRolesFlag) { // MBean no longer referenced in current relation: removes // entry mbeanRefMap.remove(relationId); } // Checks if the MBean is still referenced in at least on relation if (mbeanRefMap.isEmpty()) { // MBean no longer referenced in any relation: removes entry myRefedMBeanObjName2RelIdsMap.remove(objectName); noLongerRefFlag = true; } } RELATION_LOGGER.exiting(RelationService.class.getName(), "removeMBeanReference"); return noLongerRefFlag; } // Updates the listener registered to the MBean Server to be informed of // referenced MBean unregistrations // // -param newRefList ArrayList of ObjectNames for new references done // to MBeans (can be null) // -param obsoleteRefList ArrayList of ObjectNames for obsolete references // to MBeans (can be null) // // -exception RelationServiceNotRegisteredException if the Relation // Service is not registered in the MBean Server. private void updateUnregistrationListener(List<ObjectName> newRefList, List<ObjectName> obsoleteRefList) throws RelationServiceNotRegisteredException { if (newRefList != null && obsoleteRefList != null) { if (newRefList.isEmpty() && obsoleteRefList.isEmpty()) { // Nothing to do :) return; } } RELATION_LOGGER.entering(RelationService.class.getName(), "updateUnregistrationListener", new Object[] {newRefList, obsoleteRefList}); // Can throw RelationServiceNotRegisteredException isActive(); if (newRefList != null || obsoleteRefList != null) { boolean newListenerFlag = false; if (myUnregNtfFilter == null) { // Initialize it to be able to synchronise it :) myUnregNtfFilter = new MBeanServerNotificationFilter(); newListenerFlag = true; } synchronized(myUnregNtfFilter) { // Enables ObjectNames in newRefList if (newRefList != null) { for (ObjectName newObjName : newRefList) myUnregNtfFilter.enableObjectName(newObjName); } if (obsoleteRefList != null) { // Disables ObjectNames in obsoleteRefList for (ObjectName obsObjName : obsoleteRefList) myUnregNtfFilter.disableObjectName(obsObjName); } // Under test if (newListenerFlag) { try { myMBeanServer.addNotificationListener( MBeanServerDelegate.DELEGATE_NAME, this, myUnregNtfFilter, null); } catch (InstanceNotFoundException exc) { throw new RelationServiceNotRegisteredException(exc.getMessage()); } } // End test // if (!newListenerFlag) { // The Relation Service was already registered as a // listener: // removes it // Shall not throw InstanceNotFoundException (as the // MBean Server Delegate is expected to exist) or // ListenerNotFoundException (as it has been checked above // that the Relation Service is registered) // try { // myMBeanServer.removeNotificationListener( // MBeanServerDelegate.DELEGATE_NAME, // this); // } catch (InstanceNotFoundException exc1) { // throw new RuntimeException(exc1.getMessage()); // } catch (ListenerNotFoundException exc2) { // throw new // RelationServiceNotRegisteredException(exc2.getMessage()); // } // } // Adds Relation Service with current filter // Can throw InstanceNotFoundException if the Relation // Service is not registered, to be transformed into // RelationServiceNotRegisteredException // // Assume that there will not be any InstanceNotFoundException // for the MBean Server Delegate :) // try { // myMBeanServer.addNotificationListener( // MBeanServerDelegate.DELEGATE_NAME, // this, // myUnregNtfFilter, // null); // } catch (InstanceNotFoundException exc) { // throw new // RelationServiceNotRegisteredException(exc.getMessage()); // } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "updateUnregistrationListener"); return; } // Adds a relation (being either a RelationSupport object or an MBean // referenced using its ObjectName) in the Relation Service. // Will send a notification RelationNotification with type: // - RelationNotification.RELATION_BASIC_CREATION for internal relation // creation // - RelationNotification.RELATION_MBEAN_CREATION for an MBean being added // as a relation. // // -param relationBaseFlag flag true if the relation is a RelationSupport // object, false if it is an MBean // -param relationObj RelationSupport object (if relation is internal) // -param relationObjName ObjectName of the MBean to be added as a relation // (only for the relation MBean) // -param relationId relation identifier, to uniquely identify the relation // inside the Relation Service // -param relationTypeName name of the relation type (has to be created // in the Relation Service) // -param roleList role list to initialize roles of the relation // (can be null) // // -exception IllegalArgumentException if null paramater // -exception RelationServiceNotRegisteredException if the Relation // Service is not registered in the MBean Server // -exception RoleNotFoundException if a value is provided for a role // that does not exist in the relation type // -exception InvalidRelationIdException if relation id already used // -exception RelationTypeNotFoundException if relation type not known in // Relation Service // -exception InvalidRoleValueException if: // - the same role name is used for two different roles // - the number of referenced MBeans in given value is less than // expected minimum degree // - the number of referenced MBeans in provided value exceeds expected // maximum degree // - one referenced MBean in the value is not an Object of the MBean // class expected for that role // - an MBean provided for that role does not exist private void addRelationInt(boolean relationBaseFlag, RelationSupport relationObj, ObjectName relationObjName, String relationId, String relationTypeName, RoleList roleList) throws IllegalArgumentException, RelationServiceNotRegisteredException, RoleNotFoundException, InvalidRelationIdException, RelationTypeNotFoundException, InvalidRoleValueException { if (relationId == null || relationTypeName == null || (relationBaseFlag && (relationObj == null || relationObjName != null)) || (!relationBaseFlag && (relationObjName == null || relationObj != null))) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "addRelationInt", new Object[] {relationBaseFlag, relationObj, relationObjName, relationId, relationTypeName, roleList}); // Can throw RelationServiceNotRegisteredException isActive(); // Checks if there is already a relation with given id try { // Can throw a RelationNotFoundException (in fact should :) Object rel = getRelation(relationId); if (rel != null) { // There is already a relation with that id String excMsg = "There is already a relation with id "; StringBuilder excMsgStrB = new StringBuilder(excMsg); excMsgStrB.append(relationId); throw new InvalidRelationIdException(excMsgStrB.toString()); } } catch (RelationNotFoundException exc) { // OK : The Relation could not be found. } // Retrieves the relation type // Can throw RelationTypeNotFoundException RelationType relType = getRelationType(relationTypeName); // Checks that each provided role conforms to its role info provided in // the relation type // First retrieves a local list of the role infos of the relation type // to see which roles have not been initialized // Note: no need to test if list not null before cloning, not allowed // to have an empty relation type. List<RoleInfo> roleInfoList = new ArrayList<RoleInfo>(relType.getRoleInfos()); if (roleList != null) { for (Role currRole : roleList.asList()) { String currRoleName = currRole.getRoleName(); List<ObjectName> currRoleValue = currRole.getRoleValue(); // Retrieves corresponding role info // Can throw a RoleInfoNotFoundException to be converted into a // RoleNotFoundException RoleInfo roleInfo; try { roleInfo = relType.getRoleInfo(currRoleName); } catch (RoleInfoNotFoundException exc) { throw new RoleNotFoundException(exc.getMessage()); } // Checks that role conforms to role info, Integer status = checkRoleInt(2, currRoleName, currRoleValue, roleInfo, false); int pbType = status.intValue(); if (pbType != 0) { // A problem has occurred: throws appropriate exception // here InvalidRoleValueException throwRoleProblemException(pbType, currRoleName); } // Removes role info for that list from list of role infos for // roles to be defaulted int roleInfoIdx = roleInfoList.indexOf(roleInfo); // Note: no need to check if != -1, MUST be there :) roleInfoList.remove(roleInfoIdx); } } // Initializes roles not initialized by roleList // Can throw InvalidRoleValueException initializeMissingRoles(relationBaseFlag, relationObj, relationObjName, relationId, relationTypeName, roleInfoList); // Creation of relation successfull!!!! // Updates internal maps // Relation id to object map synchronized(myRelId2ObjMap) { if (relationBaseFlag) { // Note: do not clone relation object, created by us :) myRelId2ObjMap.put(relationId, relationObj); } else { myRelId2ObjMap.put(relationId, relationObjName); } } // Relation id to relation type name map synchronized(myRelId2RelTypeMap) { myRelId2RelTypeMap.put(relationId, relationTypeName); } // Relation type to relation id map synchronized(myRelType2RelIdsMap) { List<String> relIdList = myRelType2RelIdsMap.get(relationTypeName); boolean firstRelFlag = false; if (relIdList == null) { firstRelFlag = true; relIdList = new ArrayList<String>(); } relIdList.add(relationId); if (firstRelFlag) { myRelType2RelIdsMap.put(relationTypeName, relIdList); } } // Referenced MBean to relation id map // Only role list parameter used, as default initialization of roles // done automatically in initializeMissingRoles() sets each // uninitialized role to an empty value. for (Role currRole : roleList.asList()) { // Creates a dummy empty ArrayList of ObjectNames to be the old // role value :) List<ObjectName> dummyList = new ArrayList<ObjectName>(); // Will not throw a RelationNotFoundException (as the RelId2Obj map // has been updated above) so catch it :) try { updateRoleMap(relationId, currRole, dummyList); } catch (RelationNotFoundException exc) { // OK : The Relation could not be found. } } // Sends a notification for relation creation // Will not throw RelationNotFoundException so catch it :) try { sendRelationCreationNotification(relationId); } catch (RelationNotFoundException exc) { // OK : The Relation could not be found. } RELATION_LOGGER.exiting(RelationService.class.getName(), "addRelationInt"); return; } // Checks that given role conforms to given role info. // // -param chkType type of check: // - 1: read, just check read access // - 2: write, check value and write access if writeChkFlag // -param roleName role name // -param roleValue role value // -param roleInfo corresponding role info // -param writeChkFlag boolean to specify a current write access and // to check it // // -return Integer with value: // - 0: ok // - RoleStatus.NO_ROLE_WITH_NAME // - RoleStatus.ROLE_NOT_READABLE // - RoleStatus.ROLE_NOT_WRITABLE // - RoleStatus.LESS_THAN_MIN_ROLE_DEGREE // - RoleStatus.MORE_THAN_MAX_ROLE_DEGREE // - RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS // - RoleStatus.REF_MBEAN_NOT_REGISTERED // // -exception IllegalArgumentException if null parameter private Integer checkRoleInt(int chkType, String roleName, List<ObjectName> roleValue, RoleInfo roleInfo, boolean writeChkFlag) throws IllegalArgumentException { if (roleName == null || roleInfo == null || (chkType == 2 && roleValue == null)) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "checkRoleInt", new Object[] {chkType, roleName, roleValue, roleInfo, writeChkFlag}); // Compares names String expName = roleInfo.getName(); if (!(roleName.equals(expName))) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME); } // Checks read access if required if (chkType == 1) { boolean isReadable = roleInfo.isReadable(); if (!isReadable) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return Integer.valueOf(RoleStatus.ROLE_NOT_READABLE); } else { // End of check :) RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(0); } } // Checks write access if required if (writeChkFlag) { boolean isWritable = roleInfo.isWritable(); if (!isWritable) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(RoleStatus.ROLE_NOT_WRITABLE); } } int refNbr = roleValue.size(); // Checks minimum cardinality boolean chkMinFlag = roleInfo.checkMinDegree(refNbr); if (!chkMinFlag) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(RoleStatus.LESS_THAN_MIN_ROLE_DEGREE); } // Checks maximum cardinality boolean chkMaxFlag = roleInfo.checkMaxDegree(refNbr); if (!chkMaxFlag) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(RoleStatus.MORE_THAN_MAX_ROLE_DEGREE); } // Verifies that each referenced MBean is registered in the MBean // Server and that it is an instance of the class specified in the // role info, or of a subclass of it // Note that here again this is under the assumption that // referenced MBeans, relation MBeans and the Relation Service are // registered in the same MBean Server. String expClassName = roleInfo.getRefMBeanClassName(); for (ObjectName currObjName : roleValue) { // Checks it is registered if (currObjName == null) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED); } // Checks if it is of the correct class // Can throw an InstanceNotFoundException, if MBean not registered try { boolean classSts = myMBeanServer.isInstanceOf(currObjName, expClassName); if (!classSts) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS); } } catch (InstanceNotFoundException exc) { RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED); } } RELATION_LOGGER.exiting(RelationService.class.getName(), "checkRoleInt"); return new Integer(0); } // Initializes roles associated to given role infos to default value (empty // ArrayList of ObjectNames) in given relation. // It will succeed for every role except if the role info has a minimum // cardinality greater than 0. In that case, an InvalidRoleValueException // will be raised. // // -param relationBaseFlag flag true if the relation is a RelationSupport // object, false if it is an MBean // -param relationObj RelationSupport object (if relation is internal) // -param relationObjName ObjectName of the MBean to be added as a relation // (only for the relation MBean) // -param relationId relation id // -param relationTypeName name of the relation type (has to be created // in the Relation Service) // -param roleInfoList list of role infos for roles to be defaulted // // -exception IllegalArgumentException if null paramater // -exception RelationServiceNotRegisteredException if the Relation // Service is not registered in the MBean Server // -exception InvalidRoleValueException if role must have a non-empty // value // Revisit [cebro] Handle CIM qualifiers as REQUIRED to detect roles which // should have been initialized by the user private void initializeMissingRoles(boolean relationBaseFlag, RelationSupport relationObj, ObjectName relationObjName, String relationId, String relationTypeName, List<RoleInfo> roleInfoList) throws IllegalArgumentException, RelationServiceNotRegisteredException, InvalidRoleValueException { if ((relationBaseFlag && (relationObj == null || relationObjName != null)) || (!relationBaseFlag && (relationObjName == null || relationObj != null)) || relationId == null || relationTypeName == null || roleInfoList == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "initializeMissingRoles", new Object[] {relationBaseFlag, relationObj, relationObjName, relationId, relationTypeName, roleInfoList}); // Can throw RelationServiceNotRegisteredException isActive(); // For each role info (corresponding to a role not initialized by the // role list provided by the user), try to set in the relation a role // with an empty list of ObjectNames. // A check is performed to verify that the role can be set to an // empty value, according to its minimum cardinality for (RoleInfo currRoleInfo : roleInfoList) { String roleName = currRoleInfo.getName(); // Creates an empty value List<ObjectName> emptyValue = new ArrayList<ObjectName>(); // Creates a role Role role = new Role(roleName, emptyValue); if (relationBaseFlag) { // Internal relation // Can throw InvalidRoleValueException // // Will not throw RoleNotFoundException (role to be // initialized), or RelationNotFoundException, or // RelationTypeNotFoundException try { relationObj.setRoleInt(role, true, this, false); } catch (RoleNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (RelationNotFoundException exc2) { throw new RuntimeException(exc2.getMessage()); } catch (RelationTypeNotFoundException exc3) { throw new RuntimeException(exc3.getMessage()); } } else { // Relation is an MBean // Use standard setRole() Object[] params = new Object[1]; params[0] = role; String[] signature = new String[1]; signature[0] = "javax.management.relation.Role"; // Can throw MBeanException wrapping // InvalidRoleValueException. Returns the target exception to // be homogeneous. // // Will not throw MBeanException (wrapping // RoleNotFoundException or MBeanException) or // InstanceNotFoundException, or ReflectionException // // Again here the assumption is that the Relation Service and // the relation MBeans are registered in the same MBean Server. try { myMBeanServer.setAttribute(relationObjName, new Attribute("Role", role)); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc3) { throw new RuntimeException(exc3.getMessage()); } catch (MBeanException exc2) { Exception wrappedExc = exc2.getTargetException(); if (wrappedExc instanceof InvalidRoleValueException) { throw ((InvalidRoleValueException)wrappedExc); } else { throw new RuntimeException(wrappedExc.getMessage()); } } catch (AttributeNotFoundException exc4) { throw new RuntimeException(exc4.getMessage()); } catch (InvalidAttributeValueException exc5) { throw new RuntimeException(exc5.getMessage()); } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "initializeMissingRoles"); return; } // Throws an exception corresponding to a given problem type // // -param pbType possible problem, defined in RoleUnresolved // -param roleName role name // // -exception IllegalArgumentException if null parameter // -exception RoleNotFoundException for problems: // - NO_ROLE_WITH_NAME // - ROLE_NOT_READABLE // - ROLE_NOT_WRITABLE // -exception InvalidRoleValueException for problems: // - LESS_THAN_MIN_ROLE_DEGREE // - MORE_THAN_MAX_ROLE_DEGREE // - REF_MBEAN_OF_INCORRECT_CLASS // - REF_MBEAN_NOT_REGISTERED static void throwRoleProblemException(int pbType, String roleName) throws IllegalArgumentException, RoleNotFoundException, InvalidRoleValueException { if (roleName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } // Exception type: 1 = RoleNotFoundException // 2 = InvalidRoleValueException int excType = 0; String excMsgPart = null; switch (pbType) { case RoleStatus.NO_ROLE_WITH_NAME: excMsgPart = " does not exist in relation."; excType = 1; break; case RoleStatus.ROLE_NOT_READABLE: excMsgPart = " is not readable."; excType = 1; break; case RoleStatus.ROLE_NOT_WRITABLE: excMsgPart = " is not writable."; excType = 1; break; case RoleStatus.LESS_THAN_MIN_ROLE_DEGREE: excMsgPart = " has a number of MBean references less than the expected minimum degree."; excType = 2; break; case RoleStatus.MORE_THAN_MAX_ROLE_DEGREE: excMsgPart = " has a number of MBean references greater than the expected maximum degree."; excType = 2; break; case RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS: excMsgPart = " has an MBean reference to an MBean not of the expected class of references for that role."; excType = 2; break; case RoleStatus.REF_MBEAN_NOT_REGISTERED: excMsgPart = " has a reference to null or to an MBean not registered."; excType = 2; break; } // No default as we must have been in one of those cases StringBuilder excMsgStrB = new StringBuilder(roleName); excMsgStrB.append(excMsgPart); String excMsg = excMsgStrB.toString(); if (excType == 1) { throw new RoleNotFoundException(excMsg); } else if (excType == 2) { throw new InvalidRoleValueException(excMsg); } } // Sends a notification of given type, with given parameters // // -param intNtfType integer to represent notification type: // - 1 : create // - 2 : update // - 3 : delete // -param message human-readable message // -param relationId relation id of the created/updated/deleted relation // -param unregMBeanList list of ObjectNames of referenced MBeans // expected to be unregistered due to relation removal (only for removal, // due to CIM qualifiers, can be null) // -param roleName role name // -param roleNewValue role new value (ArrayList of ObjectNames) // -param oldValue old role value (ArrayList of ObjectNames) // // -exception IllegalArgument if null parameter // -exception RelationNotFoundException if no relation for given id private void sendNotificationInt(int intNtfType, String message, String relationId, List<ObjectName> unregMBeanList, String roleName, List<ObjectName> roleNewValue, List<ObjectName> oldValue) throws IllegalArgumentException, RelationNotFoundException { if (message == null || relationId == null || (intNtfType != 3 && unregMBeanList != null) || (intNtfType == 2 && (roleName == null || roleNewValue == null || oldValue == null))) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "sendNotificationInt", new Object[] {intNtfType, message, relationId, unregMBeanList, roleName, roleNewValue, oldValue}); // Relation type name // Note: do not use getRelationTypeName() as if it is a relation MBean // it is already unregistered. String relTypeName; synchronized(myRelId2RelTypeMap) { relTypeName = (myRelId2RelTypeMap.get(relationId)); } // ObjectName (for a relation MBean) // Can also throw a RelationNotFoundException, but detected above ObjectName relObjName = isRelationMBean(relationId); String ntfType = null; if (relObjName != null) { switch (intNtfType) { case 1: ntfType = RelationNotification.RELATION_MBEAN_CREATION; break; case 2: ntfType = RelationNotification.RELATION_MBEAN_UPDATE; break; case 3: ntfType = RelationNotification.RELATION_MBEAN_REMOVAL; break; } } else { switch (intNtfType) { case 1: ntfType = RelationNotification.RELATION_BASIC_CREATION; break; case 2: ntfType = RelationNotification.RELATION_BASIC_UPDATE; break; case 3: ntfType = RelationNotification.RELATION_BASIC_REMOVAL; break; } } // Sequence number Long seqNo = atomicSeqNo.incrementAndGet(); // Timestamp Date currDate = new Date(); long timeStamp = currDate.getTime(); RelationNotification ntf = null; if (ntfType.equals(RelationNotification.RELATION_BASIC_CREATION) || ntfType.equals(RelationNotification.RELATION_MBEAN_CREATION) || ntfType.equals(RelationNotification.RELATION_BASIC_REMOVAL) || ntfType.equals(RelationNotification.RELATION_MBEAN_REMOVAL)) // Creation or removal ntf = new RelationNotification(ntfType, this, seqNo.longValue(), timeStamp, message, relationId, relTypeName, relObjName, unregMBeanList); else if (ntfType.equals(RelationNotification.RELATION_BASIC_UPDATE) || ntfType.equals(RelationNotification.RELATION_MBEAN_UPDATE)) { // Update ntf = new RelationNotification(ntfType, this, seqNo.longValue(), timeStamp, message, relationId, relTypeName, relObjName, roleName, roleNewValue, oldValue); } sendNotification(ntf); RELATION_LOGGER.exiting(RelationService.class.getName(), "sendNotificationInt"); return; } // Checks, for the unregistration of an MBean referenced in the roles given // in parameter, if the relation has to be removed or not, regarding // expected minimum role cardinality and current number of // references in each role after removal of the current one. // If the relation is kept, calls handleMBeanUnregistration() callback of // the relation to update it. // // -param relationId relation id // -param objectName ObjectName of the unregistered MBean // -param roleNameList list of names of roles where the unregistered // MBean is referenced. // // -exception IllegalArgumentException if null parameter // -exception RelationServiceNotRegisteredException if the Relation // Service is not registered in the MBean Server // -exception RelationNotFoundException if unknown relation id // -exception RoleNotFoundException if one role given as parameter does // not exist in the relation private void handleReferenceUnregistration(String relationId, ObjectName objectName, List<String> roleNameList) throws IllegalArgumentException, RelationServiceNotRegisteredException, RelationNotFoundException, RoleNotFoundException { if (relationId == null || roleNameList == null || objectName == null) { String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } RELATION_LOGGER.entering(RelationService.class.getName(), "handleReferenceUnregistration", new Object[] {relationId, objectName, roleNameList}); // Can throw RelationServiceNotRegisteredException isActive(); // Retrieves the relation type name of the relation // Can throw RelationNotFoundException String currRelTypeName = getRelationTypeName(relationId); // Retrieves the relation // Can throw RelationNotFoundException, but already detected above Object relObj = getRelation(relationId); // Flag to specify if the relation has to be deleted boolean deleteRelFlag = false; for (String currRoleName : roleNameList) { if (deleteRelFlag) { break; } // Retrieves number of MBeans currently referenced in role // BEWARE! Do not use getRole() as role may be not readable // // Can throw RelationNotFoundException (but already checked), // RoleNotFoundException int currRoleRefNbr = (getRoleCardinality(relationId, currRoleName)).intValue(); // Retrieves new number of element in role int currRoleNewRefNbr = currRoleRefNbr - 1; // Retrieves role info for that role // // Shall not throw RelationTypeNotFoundException or // RoleInfoNotFoundException RoleInfo currRoleInfo; try { currRoleInfo = getRoleInfo(currRelTypeName, currRoleName); } catch (RelationTypeNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (RoleInfoNotFoundException exc2) { throw new RuntimeException(exc2.getMessage()); } // Checks with expected minimum number of elements boolean chkMinFlag = currRoleInfo.checkMinDegree(currRoleNewRefNbr); if (!chkMinFlag) { // The relation has to be deleted deleteRelFlag = true; } } if (deleteRelFlag) { // Removes the relation removeRelation(relationId); } else { // Updates each role in the relation using // handleMBeanUnregistration() callback // // BEWARE: this roleNameList list MUST BE A COPY of a role name // list for a referenced MBean in a relation, NOT a // reference to an original one part of the // myRefedMBeanObjName2RelIdsMap!!!! Because each role // which name is in that list will be updated (potentially // using setRole(). So the Relation Service will update the // myRefedMBeanObjName2RelIdsMap to refelect the new role // value! for (String currRoleName : roleNameList) { if (relObj instanceof RelationSupport) { // Internal relation // Can throw RoleNotFoundException (but already checked) // // Shall not throw // RelationTypeNotFoundException, // InvalidRoleValueException (value was correct, removing // one reference shall not invalidate it, else detected // above) try { ((RelationSupport)relObj).handleMBeanUnregistrationInt( objectName, currRoleName, true, this); } catch (RelationTypeNotFoundException exc3) { throw new RuntimeException(exc3.getMessage()); } catch (InvalidRoleValueException exc4) { throw new RuntimeException(exc4.getMessage()); } } else { // Relation MBean Object[] params = new Object[2]; params[0] = objectName; params[1] = currRoleName; String[] signature = new String[2]; signature[0] = "javax.management.ObjectName"; signature[1] = "java.lang.String"; // Shall not throw InstanceNotFoundException, or // MBeanException (wrapping RoleNotFoundException or // MBeanException or InvalidRoleValueException) or // ReflectionException try { myMBeanServer.invoke(((ObjectName)relObj), "handleMBeanUnregistration", params, signature); } catch (InstanceNotFoundException exc1) { throw new RuntimeException(exc1.getMessage()); } catch (ReflectionException exc3) { throw new RuntimeException(exc3.getMessage()); } catch (MBeanException exc2) { Exception wrappedExc = exc2.getTargetException(); throw new RuntimeException(wrappedExc.getMessage()); } } } } RELATION_LOGGER.exiting(RelationService.class.getName(), "handleReferenceUnregistration"); return; } }