0001: /**
0002: * Copyright (C) The MX4J Contributors.
0003: * All rights reserved.
0004: *
0005: * This software is distributed under the terms of the MX4J License version 1.0.
0006: * See the terms of the MX4J License in the documentation provided with this software.
0007: */package javax.management.relation;
0008:
0009: import java.util.ArrayList;
0010: import java.util.Date;
0011: import java.util.HashMap;
0012: import java.util.Iterator;
0013: import java.util.List;
0014: import java.util.Map;
0015: import java.util.Set;
0016: import javax.management.InstanceNotFoundException;
0017: import javax.management.MBeanNotificationInfo;
0018: import javax.management.MBeanRegistration;
0019: import javax.management.MBeanServer;
0020: import javax.management.MBeanServerInvocationHandler;
0021: import javax.management.MBeanServerNotification;
0022: import javax.management.MalformedObjectNameException;
0023: import javax.management.Notification;
0024: import javax.management.NotificationBroadcasterSupport;
0025: import javax.management.NotificationListener;
0026: import javax.management.ObjectName;
0027: import javax.management.RuntimeOperationsException;
0028:
0029: import mx4j.log.Log;
0030: import mx4j.log.Logger;
0031:
0032: /**
0033: * @version $Revision: 1.35 $
0034: */
0035:
0036: /**
0037: * An MBean that maintains the consistency of all relation types and all relation instances within a JMX agent.
0038: * It provides query operations to fins related and associated mbeans and their roles in the relation.
0039: */
0040: public class RelationService extends NotificationBroadcasterSupport
0041: implements RelationServiceMBean, MBeanRegistration,
0042: NotificationListener {
0043: private boolean m_purgeFlag;
0044: private Long m_notificationCounter = new Long(0);
0045:
0046: private MBeanServer m_server = null;
0047: private RelationSupportMBean m_proxy = null;
0048: private ObjectName m_relationServiceObjectName = null;
0049:
0050: private MBeanServerNotificationFilter m_notificationFilter = null;
0051:
0052: private Map m_relationIdToRelationObject = new HashMap();
0053: private Map m_relationIdToRelationTypeName = new HashMap();
0054: private Map m_relationMBeanObjectNameToRelationId = new HashMap();
0055: private Map m_relationTypeNameToRelationTypeObject = new HashMap();
0056: private Map m_relationTypeNameToRelationIds = new HashMap();
0057: private Map m_referencedMBeanObjectNameToRelationIds = new HashMap();
0058:
0059: private List m_deregisteredNotificationList = new ArrayList();
0060:
0061: /**
0062: * constructor
0063: *
0064: * @param purgeFlag - this is a flag, if true indicates an immediate update of relations is to be done when a
0065: * notification is recieved for the unregistration of an MBean referenced in a relation
0066: * - if false update of relations must be performed explicitly by calling purgeRelations()
0067: * @see #purgeRelations
0068: */
0069: public RelationService(boolean purgeFlag) {
0070: m_purgeFlag = purgeFlag;
0071: }
0072:
0073: /**
0074: * @throws RelationServiceNotRegisteredException
0075: * - thrown if the RelationService is not registered in the MBeanServer
0076: * <p>Currently this class must be registered in the MBeanServer before any relations can be created or added</p>
0077: */
0078: public void isActive() throws RelationServiceNotRegisteredException {
0079: Logger logger = getLogger();
0080: if (m_server == null) {
0081: logger
0082: .error("RelationService has not been registered in the MBeanServer");
0083: throw new RelationServiceNotRegisteredException(
0084: "Relation Service is not registered");
0085: }
0086: }
0087:
0088: /**
0089: * @return true - if the purgeFlag has been set, false if updates of a relation must be called explicitly
0090: * @see #purgeRelations
0091: */
0092: public boolean getPurgeFlag() {
0093: return m_purgeFlag;
0094: }
0095:
0096: /**
0097: * @param purgeFlag - a flag that when set to true indicates to the <code>RelationService</code> that it must update all relations
0098: * when it recieves a unregistration notification
0099: * if false this will not occur and purgeRelations must be called explicitly
0100: */
0101: public void setPurgeFlag(boolean purgeFlag) {
0102: m_purgeFlag = purgeFlag;
0103: }
0104:
0105: /**
0106: * @param relationTypeName - a string giving relations a type name this must be a unique name
0107: * @param roleInfos - an array of RoleInfo objects.
0108: * Which are used to define the roles a relation plays a part in. It defines attributes
0109: * such as cardinality, role reading and writing...
0110: * The RelationService will then use these RoleInfo to maintain the relation
0111: * @throws IllegalArgumentException - thrown if any of the parameters are null
0112: * @throws InvalidRelationTypeException - thrown if the role name, contained in the RoleInfo, already exists.
0113: * <p/>
0114: * <p>This method creates a relationType (a RelationTypeSupport Object) from the parameters passed in.</p>
0115: * <p>The RelationTypeSupport represents an internal relation</p>
0116: */
0117: public void createRelationType(String relationTypeName,
0118: RoleInfo[] roleInfos) throws IllegalArgumentException,
0119: InvalidRelationTypeException {
0120: if (relationTypeName == null)
0121: throw new IllegalArgumentException(
0122: "Illegal Null Relation Type Name value");
0123: if (roleInfos == null)
0124: throw new IllegalArgumentException("Illegal Null RoleInfo");
0125:
0126: Logger logger = getLogger();
0127: if (logger.isEnabledFor(Logger.DEBUG))
0128: logger
0129: .debug("Creating Relation Type with relationTypeName: "
0130: + relationTypeName);
0131:
0132: RelationTypeSupport relationType = new RelationTypeSupport(
0133: relationTypeName, roleInfos);
0134: // created a new RelationType add it to our map
0135: addRelationTypeToMap(relationTypeName, relationType);
0136: }
0137:
0138: /* Adds a relationTypeName as the key to a Map and the RelationType as the value */
0139: private void addRelationTypeToMap(String relationTypeName,
0140: RelationType relationType)
0141: throws InvalidRelationTypeException {
0142: Logger logger = getLogger();
0143: // synchronize all activities to map.
0144: synchronized (m_relationTypeNameToRelationTypeObject) {
0145: if ((m_relationTypeNameToRelationTypeObject
0146: .get(relationTypeName)) != null) {
0147: logger
0148: .warn("Cannot addRelationType as a relationType of the same name: "
0149: + relationTypeName
0150: + " already exists in the RelationService");
0151: throw new InvalidRelationTypeException(
0152: "RelationType with name: "
0153: + relationTypeName
0154: + " already exists in the RelationService");
0155: }
0156: // set the RelationTypeSupport internal flag to true indicating that the relationType has been declared in the relation service
0157: if (relationType instanceof RelationTypeSupport) {
0158: ((RelationTypeSupport) relationType)
0159: .setRelationServiceFlag(true);
0160: }
0161: // store the instance in the map
0162: m_relationTypeNameToRelationTypeObject.put(
0163: relationTypeName, relationType);
0164: }
0165: }
0166:
0167: /* returns the RelationType stored in the Map given the relationTypeName */
0168: private RelationType getRelationType(String relationTypeName)
0169: throws IllegalArgumentException,
0170: RelationTypeNotFoundException {
0171: RelationType relationType;
0172: synchronized (m_relationTypeNameToRelationTypeObject) {
0173: relationType = ((RelationType) (m_relationTypeNameToRelationTypeObject
0174: .get(relationTypeName)));
0175: // exception is caught by calling classes testing for RelationTypeNotFound.
0176: if (relationType == null) {
0177: throw new RelationTypeNotFoundException(
0178: "No RelationType found for relationTypeName: "
0179: + relationTypeName);
0180: }
0181: return relationType;
0182: }
0183: }
0184:
0185: /**
0186: * @param relationType - an Object implementing the RelationType interface a utility implementation is provided by the
0187: * <code>RelationTypeSupport</code> class
0188: * @throws IllegalArgumentException if a null RelationType is passed in as a parameter or if that RelationType has no RoleInfo defined
0189: * @throws InvalidRelationTypeException if the RoleInfo obtained from the RelationType is
0190: * - empty
0191: * - null
0192: * - the RoleName is already in use
0193: * <p>This method makes an externally defined relation type available through the relationService</p>
0194: * <p>The RelationType is immutable, hence the returned values should never change while the relationType is registered
0195: * with the realtion service</p>
0196: */
0197: public void addRelationType(RelationType relationType)
0198: throws IllegalArgumentException,
0199: InvalidRelationTypeException {
0200: if (relationType == null)
0201: throw new IllegalArgumentException(
0202: "Relation Type should not be null.");
0203:
0204: // check type name
0205: String relationTypeName = relationType.getRelationTypeName();
0206: if (relationTypeName == null)
0207: throw new IllegalArgumentException(
0208: "RelationTypeName must not be null");
0209:
0210: Logger logger = getLogger();
0211: if (logger.isEnabledFor(Logger.DEBUG))
0212: logger.debug("Adding a RelationType");
0213:
0214: List roleInfoList = relationType.getRoleInfos();
0215: if (roleInfoList == null) {
0216: logger
0217: .warn("Cannot add RelationType: "
0218: + relationType.getClass().getName()
0219: + " RoleInfo information was not provided with the RelationType.");
0220: throw new InvalidRelationTypeException(
0221: "No RoleInfo provided with Relation Type");
0222: }
0223: // build the roleInfo[] to validate the RoleInfo
0224: RoleInfo[] roleInfos = new RoleInfo[roleInfoList.size()];
0225: int index = 0;
0226: for (Iterator i = roleInfoList.iterator(); i.hasNext();) {
0227: RoleInfo currentRoleInfo = (RoleInfo) i.next();
0228: roleInfos[index] = currentRoleInfo;
0229: index++;
0230: }
0231: // need to validateRoleInfos before adding
0232: RelationTypeSupport.checkRoleInfos(roleInfos);
0233:
0234: // validated add the RelationType
0235: addRelationTypeToMap(relationTypeName, relationType);
0236: }
0237:
0238: /**
0239: * @return a list containing all the relationTypeNames registered with the relation service
0240: */
0241: public List getAllRelationTypeNames() {
0242: List result;
0243: synchronized (m_relationTypeNameToRelationTypeObject) {
0244: result = new ArrayList(
0245: m_relationTypeNameToRelationTypeObject.keySet());
0246: }
0247: // return all relationTypeNames or an empty list if none
0248: return result;
0249: }
0250:
0251: /**
0252: * @param relationTypeName - the string name representation of this RelationType
0253: * @return - List containing the RoleInfos for this RelationType Object
0254: * @throws IllegalArgumentException - if the relationTypeName is null
0255: * @throws RelationTypeNotFoundException - if the Relationtype for the given relationTypeName is not found
0256: */
0257: public List getRoleInfos(String relationTypeName)
0258: throws IllegalArgumentException,
0259: RelationTypeNotFoundException {
0260: if (relationTypeName == null)
0261: throw new IllegalArgumentException(
0262: "Illegal relationType name is null.");
0263: RelationType relationType = getRelationType(relationTypeName);
0264: // returns a List of RoleInfo objects
0265: return relationType.getRoleInfos();
0266: }
0267:
0268: /**
0269: * @param relationTypeName - string name representing the RelationType
0270: * @param roleInfoName - string name representing the RoleInfo object
0271: * @return - the corresponding RoleInfo Object for the given parameters
0272: * @throws IllegalArgumentException - if either the relationtypeName or the roleInfoName is null
0273: * @throws RelationTypeNotFoundException - if the RelationType is not in the realtion service
0274: * @throws RoleInfoNotFoundException - if the RoleInfo has not been found
0275: */
0276: public RoleInfo getRoleInfo(String relationTypeName,
0277: String roleInfoName) throws IllegalArgumentException,
0278: RelationTypeNotFoundException, RoleInfoNotFoundException {
0279: if (relationTypeName == null)
0280: throw new IllegalArgumentException(
0281: "Null relation type name");
0282: if (roleInfoName == null)
0283: throw new IllegalArgumentException("Null RoleInfo name");
0284: // gets the RelationType then gets the RoleInfo object
0285: return (getRelationType(relationTypeName)
0286: .getRoleInfo(roleInfoName));
0287: }
0288:
0289: /**
0290: * @param relationTypeName - a string name representing the Relationtype Object
0291: * @throws IllegalArgumentException - if the relationTypeName is null
0292: * @throws RelationServiceNotRegisteredException
0293: * - if the RelationService has not been registered in the MBeanServer
0294: * @throws RelationTypeNotFoundException - if the RelationType has not been found
0295: * <p/>
0296: * <p>This method removes a RelationType, it's name(represented by the relationTypeName) and any relationIds associated with it,
0297: * and all MBeans referenced in it's roles</p>
0298: * <p>Note: this will not remove any mbeans registered with the MBeanServer this must be done if required via the MBeanServer.
0299: * Any Mbeans registered with the MBean server will continue to be accessed via the MBeanServer, they will no longer be able to be
0300: * referenced, queried via the relation service though.</p>
0301: */
0302: public void removeRelationType(String relationTypeName)
0303: throws IllegalArgumentException,
0304: RelationServiceNotRegisteredException,
0305: RelationTypeNotFoundException {
0306: Logger logger = getLogger();
0307: isActive();
0308: if (relationTypeName == null)
0309: throw new IllegalArgumentException(
0310: "Illegal: relationType name cannot be null.");
0311: if (logger.isEnabledFor(Logger.DEBUG))
0312: logger
0313: .debug("Removing RelationType with relationTypeName: "
0314: + relationTypeName);
0315:
0316: // will throw RelationTypeNotFoundException if not found
0317: getRelationType(relationTypeName);
0318:
0319: // no need to clone as relationIdList is internal and get its values from a private method.
0320: List relationIdList = getRelationIds(relationTypeName);
0321:
0322: removeRelationTypeObject(relationTypeName);
0323: removeRelationTypeName(relationTypeName);
0324:
0325: if (relationIdList != null) {
0326: for (Iterator i = relationIdList.iterator(); i.hasNext();) {
0327: String currentRelationId = (String) i.next();
0328: try {
0329: // removed the relationType now remove the relation
0330: removeRelation(currentRelationId);
0331: } catch (RelationNotFoundException ex) {
0332: throw new RuntimeOperationsException(null, ex
0333: .toString());
0334: }
0335: }
0336: }
0337: }
0338:
0339: private void removeRelationTypeObject(String relationTypeName) {
0340: synchronized (m_relationTypeNameToRelationTypeObject) {
0341: m_relationTypeNameToRelationTypeObject
0342: .remove(relationTypeName);
0343: }
0344: }
0345:
0346: private List getRelationIds(String relationTypeName) {
0347: synchronized (m_relationTypeNameToRelationIds) {
0348: return ((List) (m_relationTypeNameToRelationIds
0349: .get(relationTypeName)));
0350: }
0351: }
0352:
0353: /**
0354: * @param relationId - the id through which this relation is referenced
0355: * @param relationTypeName - a unique name for the RelationType
0356: * @param roleList - a list of roles to be associated with this relation
0357: * @throws IllegalArgumentException - if the relationId, or relationTypeName is null
0358: * @throws RelationServiceNotRegisteredException
0359: * - if the relationService has not been registered in the MBeanServer
0360: * @throws RoleNotFoundException - if a role defined in the RoleList is null or empty
0361: * @throws InvalidRelationIdException - if the relationId is already in use.
0362: * @throws RelationTypeNotFoundException - if the relationType is not found
0363: * @throws InvalidRoleValueException - if cardinality is not correct i.e min cardinality is greater than max cardinality
0364: * <p/>
0365: * <p>According to the RI spec this method is used only to create internal relations - hence creates an InternalRelation</p>
0366: * <p>This creates a relation represented by a RelationSupport Object, and a RelationNotification,
0367: * with type RELATION_BASIC_CREATION, is sent</p>
0368: */
0369: public void createRelation(String relationId,
0370: String relationTypeName, RoleList roleList)
0371: throws IllegalArgumentException,
0372: RelationServiceNotRegisteredException,
0373: RoleNotFoundException, InvalidRelationIdException,
0374: RelationTypeNotFoundException, InvalidRoleValueException {
0375: isActive();
0376: if (relationId == null)
0377: throw new IllegalArgumentException("Null Relation Id");
0378: if (relationTypeName == null)
0379: throw new IllegalArgumentException(
0380: "Null Relation Type Name");
0381: Logger logger = getLogger();
0382: if (logger.isEnabledFor(Logger.DEBUG)) {
0383: logger.debug("Creating an InternalRelation with ID: "
0384: + relationId + " and relationType name: "
0385: + relationTypeName);
0386: }
0387: // creating InternalRelation to represent the internal relations
0388: InternalRelation internalRelation = new InternalRelation(
0389: relationId, m_relationServiceObjectName,
0390: relationTypeName, roleList);
0391: try {
0392: if (getRelationObject(relationId) != null) {
0393: logger
0394: .warn("There is a Relation already registered in the RelationServcie with ID: "
0395: + relationId);
0396: throw new InvalidRelationIdException(
0397: "There is already a relation with id: "
0398: + relationId);
0399: }
0400: } catch (RelationNotFoundException ex) {/*Do nothing as should not be found*/
0401: }
0402:
0403: RelationType relationType = getRelationType(relationTypeName);
0404: ArrayList roleInfoList = (ArrayList) (buildRoleInfoList(
0405: relationType, roleList));
0406: if (!(roleInfoList.isEmpty())) {
0407: initializeMissingCreateRoles(roleInfoList,
0408: internalRelation, relationId, relationTypeName);
0409: }
0410:
0411: synchronized (m_relationIdToRelationObject) {
0412: m_relationIdToRelationObject.put(relationId,
0413: internalRelation);
0414: }
0415: addRelationId(relationId, relationTypeName);
0416: addRelationTypeName(relationId, relationTypeName);
0417: updateRoles(roleList, relationId);
0418: try {
0419: if (logger.isEnabledFor(Logger.DEBUG))
0420: logger
0421: .debug("sending RelationCreation notification to all listeners");
0422: sendRelationCreationNotification(relationId);
0423: } catch (RelationNotFoundException ex) {
0424: throw new RuntimeOperationsException(null,
0425: "Unable to send notification as Relation not found");
0426: }
0427: }
0428:
0429: /* updates roles given the roleList and the relationId */
0430: private void updateRoles(RoleList roleList, String relationId)
0431: throws RelationServiceNotRegisteredException,
0432: IllegalArgumentException {
0433: if (roleList == null)
0434: throw new IllegalArgumentException("Null RoleList");
0435: if (relationId == null)
0436: throw new IllegalArgumentException("Null relationId");
0437: for (Iterator i = roleList.iterator(); i.hasNext();) {
0438: Role currentRole = (Role) i.next();
0439: ArrayList tempList = new ArrayList();
0440: try {
0441: updateRoleMap(relationId, currentRole, tempList);
0442: } catch (RelationNotFoundException ex) {
0443: throw new RuntimeOperationsException(null,
0444: "Cannot update the roleMap as Relation not found");
0445: }
0446: }
0447: }
0448:
0449: private List buildRoleInfoList(RelationType relationType,
0450: List roleList) throws InvalidRoleValueException,
0451: RoleNotFoundException {
0452: List roleInfoList = relationType.getRoleInfos();
0453: if (roleList != null) {
0454: for (Iterator i = roleList.iterator(); i.hasNext();) {
0455: Role currentRole = (Role) i.next();
0456: String currentRoleName = currentRole.getRoleName();
0457: List currentRoleValue = currentRole.getRoleValue();
0458: RoleInfo roleInfo;
0459: try {
0460: roleInfo = relationType
0461: .getRoleInfo(currentRoleName);
0462: } catch (RoleInfoNotFoundException ex) {
0463: throw new RoleNotFoundException(ex.getMessage());
0464: }
0465: int problemType = (checkRoleCardinality(
0466: currentRoleName, currentRoleValue, roleInfo))
0467: .intValue();
0468: if (problemType != 0) {
0469: throwRoleProblemException(problemType,
0470: currentRoleName);
0471: }
0472: roleInfoList.remove(roleInfoList.indexOf(roleInfo));
0473: }
0474: }
0475: return roleInfoList;
0476: }
0477:
0478: private void addRelationTypeName(String relationId,
0479: String relationTypeName) {
0480: synchronized (m_relationTypeNameToRelationIds) {
0481: ArrayList idList = (ArrayList) m_relationTypeNameToRelationIds
0482: .get(relationTypeName);
0483: boolean isNewRelation = false;
0484: if (idList == null) {
0485: isNewRelation = true;
0486: idList = new ArrayList();
0487: }
0488: idList.add(relationId);
0489: if (isNewRelation)
0490: m_relationTypeNameToRelationIds.put(relationTypeName,
0491: idList);
0492: }
0493: }
0494:
0495: private void addRelationObjectName(String relationId,
0496: ObjectName relationObjectName) {
0497: synchronized (m_relationIdToRelationObject) {
0498: m_relationIdToRelationObject.put(relationId,
0499: relationObjectName);
0500: }
0501: }
0502:
0503: private void addRelationId(String relationId,
0504: String relationTypeName) {
0505: synchronized (m_relationIdToRelationTypeName) {
0506: m_relationIdToRelationTypeName.put(relationId,
0507: relationTypeName);
0508: }
0509: }
0510:
0511: // method gets called only for internal relations
0512: private void initializeMissingCreateRoles(List roleInfoList,
0513: InternalRelation internalRelation, String relationId,
0514: String relationTypeName)
0515: throws RelationTypeNotFoundException,
0516: RelationServiceNotRegisteredException,
0517: InvalidRoleValueException, RoleNotFoundException,
0518: IllegalArgumentException {
0519: isActive();
0520: if (roleInfoList == null)
0521: throw new IllegalArgumentException("RoleInfoList is Null");
0522: if (relationId == null)
0523: throw new IllegalArgumentException("RelationId is Null.");
0524: if (relationTypeName == null)
0525: throw new IllegalArgumentException(
0526: "Relation Type Name is Null.");
0527:
0528: for (Iterator i = roleInfoList.iterator(); i.hasNext();) {
0529: RoleInfo currentRoleInfo = (RoleInfo) i.next();
0530: String roleName = currentRoleInfo.getName();
0531:
0532: ArrayList temp = new ArrayList();
0533: Role role = new Role(roleName, temp);
0534: try {
0535: internalRelation.setRole(role);
0536: } catch (RelationNotFoundException ex) {
0537: throw new RuntimeOperationsException(null, ex
0538: .getMessage());
0539: }
0540: }
0541: }
0542:
0543: private Integer checkRoleCardinality(String roleName,
0544: List roleValue, RoleInfo roleInfo) {
0545: if (roleName == null)
0546: throw new IllegalArgumentException("Null Role Name");
0547: if (roleValue == null)
0548: throw new IllegalArgumentException("Null roleValue List");
0549: if (roleInfo == null)
0550: throw new IllegalArgumentException("Null RoleInfo");
0551: Logger logger = getLogger();
0552: if (logger.isEnabledFor(Logger.DEBUG))
0553: logger.debug("checking role cardinality");
0554:
0555: if (!(roleName.equals(roleInfo.getName()))) {
0556: logger.warn("Role does not have a valid roleName");
0557: return new Integer(RoleStatus.NO_ROLE_WITH_NAME);
0558: }
0559: if (!(roleInfo.checkMinDegree(roleValue.size()))) {
0560: logger
0561: .warn("Minimum number of references defined in the RoleInfo has fallen below minimum");
0562: return (new Integer(RoleStatus.LESS_THAN_MIN_ROLE_DEGREE));
0563: }
0564: if (!(roleInfo.checkMaxDegree(roleValue.size()))) {
0565: logger
0566: .warn("Maximum number of references defined in the RoleInfo has gone above the maximum");
0567: return new Integer(RoleStatus.MORE_THAN_MAX_ROLE_DEGREE);
0568: }
0569:
0570: String referencedClassName = roleInfo.getRefMBeanClassName();
0571: for (Iterator i = roleValue.iterator(); i.hasNext();) {
0572: ObjectName currentObjectName = (ObjectName) i.next();
0573: if (currentObjectName == null) {
0574: logger.warn("The mbean with RoleName: " + roleName
0575: + " is not registered in the MBeanServer");
0576: return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED);
0577: }
0578: if (!(m_server.isRegistered(currentObjectName))) {
0579: logger.warn("The mbean with ObjectName: "
0580: + currentObjectName.getCanonicalName()
0581: + " is not registered in the MBeanServer");
0582: return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED);
0583: }
0584: try {
0585: if (!(m_server.isInstanceOf(currentObjectName,
0586: referencedClassName))) {
0587: logger.warn("The class referenced: "
0588: + currentObjectName.toString()
0589: + " does not match the class expected: "
0590: + referencedClassName + " in RoleInfo: "
0591: + roleInfo.toString());
0592: return new Integer(
0593: RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS);
0594: }
0595: } catch (InstanceNotFoundException ex) {
0596: return null;
0597: }
0598: }
0599: return new Integer(0);
0600: }
0601:
0602: /**
0603: * @param relationMBeanObjectName - ObjectName of the relation MBean to be added
0604: * @throws IllegalArgumentException - if parameter is null
0605: * @throws RelationServiceNotRegisteredException
0606: * - if the Relation Service is not registered in the MBean Server
0607: * @throws NoSuchMethodException - If the MBean does not implement the Relation interface
0608: * @throws InvalidRelationIdException - if there is no relation identifier (ID) in the MBean
0609: * - if relation identifier (ID) is already used in the Relation Service
0610: * @throws InstanceNotFoundException - if the MBean for given ObjectName has not been registered
0611: * @throws InvalidRelationServiceException
0612: * - if no Relation Service name in MBean
0613: * - if the Relation Service name in the MBean is not the one of the current Relation Service
0614: * @throws RelationTypeNotFoundException - if no relation type name in MBean
0615: * - if the relation type name in MBean does not correspond to a relation type created in the Relation Service
0616: * @throws RoleNotFoundException - if a value is provided for a role that does not exist in the relation type
0617: * @throws InvalidRoleValueException - if the number of referenced MBeans in a role is less than expected minimum degree
0618: * - if the number of referenced MBeans in a role exceeds expected maximum degree
0619: * - if one referenced MBean in the value is not an Object of the MBean class expected for that role
0620: * - if an MBean provided for a role does not exist
0621: * <p/>
0622: * <p>Adds an MBean created by the user (and registered by him in the MBean Server) as a relation in the Relation Service </p>
0623: * <p>To be added as a relation, the MBean must conform to the following:
0624: * <ul>
0625: * <li>implement the Relation interface</li>
0626: * <li>have for RelationService ObjectName the ObjectName of current Relation Service </li>
0627: * <li>have a relation id unique and unused in current Relation Service </li>
0628: * <li>have for relation type a relation type created in the Relation Service </li>
0629: * <li>have roles conforming to the role info provided in the relation type</li>
0630: * </ul>
0631: */
0632: public void addRelation(ObjectName relationMBeanObjectName)
0633: throws IllegalArgumentException,
0634: RelationServiceNotRegisteredException,
0635: NoSuchMethodException, InvalidRelationIdException,
0636: InstanceNotFoundException, InvalidRelationServiceException,
0637: RelationTypeNotFoundException, RoleNotFoundException,
0638: InvalidRoleValueException {
0639: isActive();
0640: Logger logger = getLogger();
0641: if (logger.isEnabledFor(Logger.DEBUG))
0642: logger.debug("adding a Relation with ObjectName: "
0643: + relationMBeanObjectName.toString());
0644: // checks through the MBeanServer that the class is an instance of the Relation interface which
0645: // RelationSupport implements
0646: checkValidRelation(relationMBeanObjectName);
0647: //create the proxy
0648:
0649: m_proxy = (RelationSupportMBean) MBeanServerInvocationHandler
0650: .newProxyInstance(m_server, relationMBeanObjectName,
0651: RelationSupportMBean.class, false);
0652: // get the relationId of the class through the MBeanServer
0653: String relationId = m_proxy.getRelationId(); //getRelationIdAttribute(relationMBeanObjectName);
0654: if (relationId == null)
0655: throw new InvalidRelationIdException(
0656: "No RelationId provided");
0657: // obtains the objectname of the RelationService defined by the user
0658:
0659: ObjectName relationServiceObjectName = m_proxy
0660: .getRelationServiceName();
0661: // checks that the RelationService objectName is running in the server
0662: if (!(checkRelationServiceIsCurrent(relationServiceObjectName))) {
0663: throw new InvalidRelationServiceException(
0664: "The Relation Service referenced in the MBean is not the current one.");
0665: }
0666: // get the relationTypeName through the server for the user defined RelationSupport subclass
0667: String relationTypeName = m_proxy.getRelationTypeName();
0668: if (relationTypeName == null)
0669: throw new RelationTypeNotFoundException(
0670: "RelationType not found");
0671: // get the roles
0672: RoleList roleList = m_proxy.retrieveAllRoles();
0673: try {
0674: // already have defined relation registered cannot add another with the same id
0675: if (getRelationObject(relationId) != null)
0676: throw new InvalidRelationIdException(
0677: "Relation with ID " + relationId
0678: + " already exists");
0679: } catch (RelationNotFoundException ex) {/*Do nothing should not be found*/
0680: }
0681:
0682: RelationType relationType = getRelationType(relationTypeName);
0683: ArrayList roleInfoList = (ArrayList) buildRoleInfoList(
0684: relationType, roleList);
0685: if (!(roleInfoList.isEmpty())) {
0686: for (Iterator i = roleInfoList.iterator(); i.hasNext();) {
0687: RoleInfo currentRoleInfo = (RoleInfo) i.next();
0688: String currentRoleName = currentRoleInfo.getName();
0689: ArrayList emptyValueList = new ArrayList();
0690: Role role = new Role(currentRoleName, emptyValueList);
0691: try {
0692: m_proxy.setRole(role);
0693: } catch (RelationNotFoundException ex) {
0694: throw new RuntimeOperationsException(null, ex
0695: .getMessage());
0696: }
0697: }
0698: }
0699: // add all info to our corresponding maps
0700: updateAllInternals(relationId, relationMBeanObjectName,
0701: relationTypeName, roleList);
0702: }
0703:
0704: private void updateAllInternals(String relationId,
0705: ObjectName relationMBeanObjectName,
0706: String relationTypeName, RoleList roleList)
0707: throws RelationServiceNotRegisteredException {
0708: // adds key -> relationId value -> relationMBeanObjectName to HashMap
0709: addRelationObjectName(relationId, relationMBeanObjectName);
0710: addRelationId(relationId, relationTypeName);
0711: addRelationTypeName(relationId, relationTypeName);
0712: updateRoles(roleList, relationId);
0713: try {
0714: sendRelationCreationNotification(relationId);
0715: } catch (RelationNotFoundException ex) {
0716: throw new RuntimeOperationsException(null,
0717: "Cannot send a notification for relationId "
0718: + relationId + " as relation not found.");
0719: }
0720:
0721: synchronized (m_relationMBeanObjectNameToRelationId) {
0722: m_relationMBeanObjectNameToRelationId.put(
0723: relationMBeanObjectName, relationId);
0724: }
0725: m_proxy.setRelationServiceManagementFlag(new Boolean(true));
0726: List newReferenceList = new ArrayList();
0727: newReferenceList.add(relationMBeanObjectName);
0728: updateUnregistrationListener(newReferenceList, null);
0729: }
0730:
0731: private boolean checkRelationServiceIsCurrent(
0732: ObjectName relationServiceObjectName) {
0733: if (relationServiceObjectName == null)
0734: return false;
0735: if (!(relationServiceObjectName
0736: .equals(m_relationServiceObjectName)))
0737: return false;
0738: return true;
0739: }
0740:
0741: private void checkValidRelation(ObjectName relationMBeanObjectName)
0742: throws IllegalArgumentException, InstanceNotFoundException,
0743: NoSuchMethodException {
0744: if (relationMBeanObjectName == null)
0745: throw new IllegalArgumentException(
0746: "Cannot have a null Relation ObjectName");
0747: Logger logger = getLogger();
0748: if (!(m_server.isInstanceOf(relationMBeanObjectName,
0749: "javax.management.relation.Relation"))) {
0750: logger
0751: .warn("An MBean which is to be added as a Relation must implement the Relation interface");
0752: throw new NoSuchMethodException(
0753: "MBean does implement the Relation interface");
0754: }
0755: }
0756:
0757: /**
0758: * @param relationId - relation id identifying the relation
0759: * @return - the ObjectName corresponding to the relationId given or null if it is not found
0760: * @throws IllegalArgumentException - if a null parameter
0761: * @throws RelationNotFoundException - if there is no relation associated to that id
0762: * <p/>
0763: * <p>If the relation is represented by an MBean (created by the user and added as a relation in the Relation Service),
0764: * returns the ObjectName of the MBean</p>
0765: */
0766: public ObjectName isRelationMBean(String relationId)
0767: throws IllegalArgumentException, RelationNotFoundException {
0768: if (relationId == null)
0769: throw new IllegalArgumentException("Null Relation Id.");
0770: Object result = getRelationObject(relationId);
0771: if (result instanceof ObjectName) {
0772: return ((ObjectName) result);
0773: }
0774: return null;
0775: }
0776:
0777: /**
0778: * <p>Returns the relation id associated to the given ObjectName if the MBean has been added as a relation in the Relation Service</p>
0779: *
0780: * @param objectName - the ObjectName of supposed relation
0781: * @return - the relation id (String) or null (if the ObjectName is not a relation handled by the Relation Service)
0782: * @throws IllegalArgumentException - if the parameter is null
0783: */
0784: public String isRelation(ObjectName objectName)
0785: throws IllegalArgumentException {
0786: if (objectName == null)
0787: throw new IllegalArgumentException("Null ObjectName");
0788: return (getMBeanObjectName(objectName));
0789: }
0790:
0791: /**
0792: * <p>Checks if there is a relation identified in Relation Service with given relation id.</p>
0793: *
0794: * @param relationId - the relation id identifying the relation
0795: * @return boolean: true if there is a relation, false otherwise
0796: * @throws IllegalArgumentException - if parameter is null
0797: */
0798: public Boolean hasRelation(String relationId)
0799: throws IllegalArgumentException {
0800: if (relationId == null)
0801: throw new IllegalArgumentException("Null Relation Id");
0802: Boolean hasRelation = null;
0803: try {
0804: Object result = getRelationObject(relationId);
0805: if (result != null)
0806: hasRelation = Boolean.TRUE;
0807: } catch (RelationNotFoundException ex) {
0808: hasRelation = Boolean.FALSE;
0809: }
0810: return hasRelation;
0811: }
0812:
0813: /**
0814: * <p>Returns all the relation ids for all the relations handled by the Relation Service</p>
0815: *
0816: * @return an arrayList containing the relation ids
0817: */
0818: public List getAllRelationIds() {
0819: synchronized (m_relationIdToRelationObject) {
0820: return (new ArrayList(m_relationIdToRelationObject.keySet()));
0821: }
0822: }
0823:
0824: /**
0825: * <p>Checks if given Role can be read in a relation of the given type</p>
0826: *
0827: * @param roleName - name of role to be checked
0828: * @param relationTypeName - name of the relation type
0829: * @return - an Integer wrapping an integer corresponding to possible problems represented as constants in RoleUnresolved:
0830: * <ul>
0831: * <li>0 if role can be read </li>
0832: * <li>integer corresponding to RoleStatus.NO_ROLE_WITH_NAME </li>
0833: * <li>integer corresponding to RoleStatus.ROLE_NOT_READABLE </li>
0834: * </ul>
0835: * @throws IllegalArgumentException - if null parameter
0836: * @throws RelationTypeNotFoundException - if the relation type is not known in the Relation Service
0837: */
0838: public Integer checkRoleReading(String roleName,
0839: String relationTypeName) throws IllegalArgumentException,
0840: RelationTypeNotFoundException {
0841: if (roleName == null)
0842: throw new IllegalArgumentException("Null RoleName");
0843: if (relationTypeName == null)
0844: throw new IllegalArgumentException(
0845: "Null RelationType name.");
0846: Logger logger = getLogger();
0847: if (logger.isEnabledFor(Logger.DEBUG))
0848: logger.debug("checking if Role with RoleName: " + roleName
0849: + " is readable");
0850: RelationType relationType = getRelationType(relationTypeName);
0851: try {
0852: RoleInfo roleInfo = relationType.getRoleInfo(roleName);
0853: if (!(roleName.equals(roleInfo.getName())))
0854: return (new Integer(RoleStatus.NO_ROLE_WITH_NAME));
0855: if (!(roleInfo.isReadable())) {
0856: logger.warn("RoleInfo: " + roleInfo.toString()
0857: + " cannot be read");
0858: return (new Integer(RoleStatus.ROLE_NOT_READABLE));
0859: }
0860: } catch (RoleInfoNotFoundException ex) {
0861: logger.warn("roleInfo for roleName: " + roleName
0862: + " has not been found.");
0863: return (new Integer(RoleStatus.NO_ROLE_WITH_NAME));
0864: }
0865: return new Integer(0);
0866: }
0867:
0868: /**
0869: * <p>Checks if given Role can be set in a relation of given type</p>
0870: *
0871: * @param role - role to be checked
0872: * @param relationTypeName - name of relation type
0873: * @param isInitialized - flag to specify that the checking is done for the initialization of a role, write access shall not be verified
0874: * @return - an Integer wrapping an integer corresponding to possible problems represented as constants in RoleUnresolved:
0875: * <ul>
0876: * <li>0 if role can be set </li>
0877: * <li>integer corresponding to RoleStatus.NO_ROLE_WITH_NAME </li>
0878: * <li>integer for RoleStatus.ROLE_NOT_WRITABLE </li>
0879: * <li>integer for RoleStatus.LESS_THAN_MIN_ROLE_DEGREE </li>
0880: * <li>integer for RoleStatus.MORE_THAN_MAX_ROLE_DEGREE </li>
0881: * <li>integer for RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS </li>
0882: * <li>integer for RoleStatus.REF_MBEAN_NOT_REGISTERED </li>
0883: * </ul>
0884: * @throws IllegalArgumentException - if null parameter
0885: * @throws RelationTypeNotFoundException - if unknown relation type
0886: */
0887: public Integer checkRoleWriting(Role role, String relationTypeName,
0888: Boolean isInitialized) throws IllegalArgumentException,
0889: RelationTypeNotFoundException {
0890: if (role == null)
0891: throw new IllegalArgumentException(
0892: "checkRoleWriting was given a null Role");
0893: if (relationTypeName == null)
0894: throw new IllegalArgumentException(
0895: "checkRoleWriting was given a null RelationTypeName");
0896: if (isInitialized == null)
0897: throw new IllegalArgumentException(
0898: "checkRoleWriting was given a null Boolean");
0899: Logger logger = getLogger();
0900: RelationType relationType = getRelationType(relationTypeName);
0901: String roleName = role.getRoleName();
0902: if (logger.isEnabledFor(Logger.DEBUG))
0903: logger.debug("checking if Role with RoleName: " + roleName
0904: + " is readable");
0905: ArrayList roleValue = (ArrayList) role.getRoleValue();
0906: boolean canWrite = true;
0907: if (isInitialized.booleanValue())
0908: canWrite = false;
0909: RoleInfo roleInfo;
0910: try {
0911: roleInfo = relationType.getRoleInfo(roleName);
0912: } catch (RoleInfoNotFoundException ex) {
0913: logger.warn("roleInfo for roleName: " + roleName
0914: + " has not been found.");
0915: return new Integer(RoleStatus.NO_ROLE_WITH_NAME);
0916: }
0917: if (canWrite) {
0918: if (!(roleInfo.isWritable())) {
0919: logger.warn("RoleInfo: " + roleInfo.toString()
0920: + " cannot be written to.");
0921: return new Integer(RoleStatus.ROLE_NOT_WRITABLE);
0922: }
0923: }
0924: return (checkRoleCardinality(roleName, roleValue, roleInfo));
0925: }
0926:
0927: /**
0928: * <p>Sends a notification (RelationNotification) for a relation creation. The notification type is:
0929: * <ul>
0930: * <li>RelationNotification.RELATION_BASIC_CREATION if the relation is an object internal to the Relation Service </li>
0931: * <li>RelationNotification.RELATION_MBEAN_CREATION if the relation is a MBean added as a relation</li>
0932: * </ul>
0933: * The source object is the Relation Service itself<br/>
0934: * It is called in Relation Service createRelation() and addRelation() methods
0935: * </p>
0936: *
0937: * @param relationId - relation identifier of the updated relation
0938: * @throws IllegalArgumentException - if null parameter
0939: * @throws RelationNotFoundException - if there is no relation for given relation id
0940: */
0941: public void sendRelationCreationNotification(String relationId)
0942: throws IllegalArgumentException, RelationNotFoundException {
0943: if (relationId == null)
0944: throw new IllegalArgumentException("Null Relation Id.");
0945: Logger logger = getLogger();
0946: String message = "Creation of relation " + relationId;
0947: String relationTypeName = getRelationTypeNameFromMap(relationId);
0948:
0949: if (logger.isEnabledFor(Logger.DEBUG))
0950: logger.debug("A relation has been created with ID: "
0951: + relationId + " and relationTypeName: "
0952: + relationTypeName + " ..sending notification");
0953:
0954: ObjectName relationObjectName = isRelationMBean(relationId);
0955: String notificationType = getCreationNotificationType(relationObjectName);
0956: long sequenceNumber = getNotificationSequenceNumber()
0957: .longValue();
0958: Date currentDate = new Date();
0959: long timestamp = currentDate.getTime();
0960: RelationNotification relationNotification = new RelationNotification(
0961: notificationType, this , sequenceNumber, timestamp,
0962: message, relationId, relationTypeName,
0963: relationObjectName, null);
0964: sendNotification(relationNotification);
0965: }
0966:
0967: private Long getNotificationSequenceNumber() {
0968: Long result;
0969: synchronized (m_notificationCounter) {
0970: result = new Long(m_notificationCounter.longValue() + 1);
0971: m_notificationCounter = new Long(result.longValue());
0972: }
0973: return result;
0974: }
0975:
0976: private String getCreationNotificationType(
0977: ObjectName relationObjectName) {
0978: if (relationObjectName != null) {
0979: return RelationNotification.RELATION_MBEAN_CREATION;
0980: }
0981: return RelationNotification.RELATION_BASIC_CREATION;
0982: }
0983:
0984: /**
0985: * <p>Sends a notification (RelationNotification) for a role update in the given relation. The notification type is:
0986: * <ul>
0987: * <li>RelationNotification.RELATION_BASIC_UPDATE if the relation is an object internal to the Relation Service </li>
0988: * <li>RelationNotification.RELATION_MBEAN_UPDATE if the relation is a MBean added as a relation</li>
0989: * </ul></p>
0990: * <p>The source object is the Relation Service itself.</p>
0991: * <p>This method is called in relation MBean setRole() (for given role) and setRoles() (for each role) methods
0992: * (implementation provided in RelationSupport class)</p>
0993: * <p>It is also called in Relation Service setRole() (for given role) and setRoles() (for each role) methods</p>
0994: *
0995: * @param relationId - the relation identifier of the updated relation
0996: * @param newRole - new role (name and new value)
0997: * @param oldRoleValues - old role value (ArrayList of ObjectName objects)
0998: * @throws IllegalArgumentException - if null parameter
0999: * @throws RelationNotFoundException - if there is no relation for given relation id
1000: */
1001: public void sendRoleUpdateNotification(String relationId,
1002: Role newRole, List oldRoleValues)
1003: throws IllegalArgumentException, RelationNotFoundException {
1004: if (relationId == null)
1005: throw new IllegalArgumentException("Null RelationId");
1006: if (newRole == null)
1007: throw new IllegalArgumentException("Null Role");
1008: if (oldRoleValues == null)
1009: throw new IllegalArgumentException(
1010: "Null List of role values");
1011:
1012: Logger logger = getLogger();
1013: if (logger.isEnabledFor(Logger.DEBUG))
1014: logger
1015: .debug("Sending a roleUpdateNotification of Relation with ID: "
1016: + relationId);
1017: String roleName = newRole.getRoleName();
1018: List newRoleValues = newRole.getRoleValue();
1019: String newRoleValueMessage = Role
1020: .roleValueToString(newRoleValues);
1021: String oldRoleValueMessage = Role
1022: .roleValueToString(oldRoleValues);
1023: StringBuffer message = new StringBuffer("Value of the role ");
1024: message.append(roleName);
1025: message.append(" has changed\nOld value:\n");
1026: message.append(oldRoleValueMessage);
1027: message.append("\nNew value:\n");
1028: message.append(newRoleValueMessage);
1029: if (logger.isEnabledFor(Logger.DEBUG))
1030: logger.debug("Notification message: " + message.toString());
1031: String relationTypeName = getRelationTypeNameFromMap(relationId);
1032:
1033: // determine if this is a relation update or a relation mbean update
1034: ObjectName relationObjectName = isRelationMBean(relationId);
1035: String notificationType;
1036: if (relationObjectName != null)
1037: notificationType = RelationNotification.RELATION_MBEAN_UPDATE;
1038: else
1039: notificationType = RelationNotification.RELATION_BASIC_UPDATE;
1040:
1041: long sequenceNumber = getNotificationSequenceNumber()
1042: .longValue();
1043: Date currentDate = new Date();
1044: long timeStamp = currentDate.getTime();
1045:
1046: RelationNotification notification = new RelationNotification(
1047: notificationType, this , sequenceNumber, timeStamp,
1048: message.toString(), relationId, relationTypeName,
1049: relationObjectName, roleName, newRoleValues,
1050: oldRoleValues);
1051: sendNotification(notification);
1052: }
1053:
1054: /**
1055: * <p>Sends a notification (RelationNotification) for a relation removal. The notification type is:
1056: * <ul>
1057: * <li>RelationNotification.RELATION_BASIC_REMOVAL if the relation is an object internal to the Relation Service </li>
1058: * <li>RelationNotification.RELATION_MBEAN_REMOVAL if the relation is a MBean added as a relation</li>
1059: * </ul>
1060: * The source object is the Relation Service itself</p>
1061: * <p>It is called in Relation Service removeRelation() method</p>
1062: *
1063: * @param relationId - relation identifier of the updated relation
1064: * @param unregisteredMBeanList - ArrayList of ObjectNames of MBeans expected to be unregistered due to relation removal (can be null)
1065: * @throws IllegalArgumentException - if relationId is null
1066: * @throws RelationNotFoundException - if there is no relation for given relation id
1067: */
1068: public void sendRelationRemovalNotification(String relationId,
1069: List unregisteredMBeanList)
1070: throws IllegalArgumentException, RelationNotFoundException {
1071: if (relationId == null)
1072: throw new IllegalArgumentException("Null RelationId");
1073:
1074: Logger logger = getLogger();
1075: if (logger.isEnabledFor(Logger.DEBUG))
1076: logger.debug("sending relationRemovalNotification of ID: "
1077: + relationId);
1078: StringBuffer message = new StringBuffer("Removal of relation ");
1079: message.append(relationId);
1080: String relationTypeName = getRelationTypeNameFromMap(relationId);
1081: ObjectName relationObjectName = isRelationMBean(relationId);
1082: String notificationType;
1083: if (relationObjectName != null)
1084: notificationType = RelationNotification.RELATION_MBEAN_REMOVAL;
1085: else
1086: notificationType = RelationNotification.RELATION_BASIC_REMOVAL;
1087: long sequenceNumber = getNotificationSequenceNumber()
1088: .longValue();
1089: Date currentDate = new Date();
1090: long timeStamp = currentDate.getTime();
1091: RelationNotification notification = new RelationNotification(
1092: notificationType, this , sequenceNumber, timeStamp,
1093: message.toString(), relationId, relationTypeName,
1094: relationObjectName, unregisteredMBeanList);
1095:
1096: sendNotification(notification);
1097: }
1098:
1099: /**
1100: * <p>Handles update of the Relation Service role map for the update of given role in given relation</p>
1101: * <p>It is called in relation MBean setRole() (for given role) and setRoles()(for each role) methods
1102: * (implementation provided in RelationSupport class).</p>
1103: * <p>It is also called in Relation Service setRole() (for given role) and setRoles() (for each role) methods.</p>
1104: * <p>To allow the Relation Service to maintain the consistency (in case of MBean unregistration) and to be able to
1105: * perform queries, this method must be called when a role is updated. </p>
1106: *
1107: * @param relationId - relation identifier of the updated relation
1108: * @param role - new role (name and new value)
1109: * @param oldRoleValues - old role value (ArrayList of ObjectName objects)
1110: * @throws IllegalArgumentException - if null parameter
1111: * @throws RelationServiceNotRegisteredException
1112: * - if the Relation Service is not registered in the MBean Server
1113: * @throws RelationNotFoundException - if no relation for given id
1114: */
1115: public void updateRoleMap(String relationId, Role role,
1116: List oldRoleValues) throws IllegalArgumentException,
1117: RelationServiceNotRegisteredException,
1118: RelationNotFoundException {
1119: isActive();
1120: if (relationId == null)
1121: throw new IllegalArgumentException("Null Relation Id");
1122: if (role == null)
1123: throw new IllegalArgumentException("Null Role");
1124: if (oldRoleValues == null)
1125: throw new IllegalArgumentException("Null Role value list.");
1126:
1127: Logger logger = getLogger();
1128: if (logger.isEnabledFor(Logger.DEBUG))
1129: logger.debug("Updating the RelationService RoleMap");
1130:
1131: String roleName = role.getRoleName();
1132: List newRoleValue = role.getRoleValue();
1133:
1134: // clone as the list is to be modified later, cast to ArrayList as List does not define clone()
1135: List oldValues = (ArrayList) (((ArrayList) oldRoleValues)
1136: .clone());
1137:
1138: // List of ObjectNames of new referenced MBeans
1139: List newReferenceList = new ArrayList();
1140: for (Iterator i = newRoleValue.iterator(); i.hasNext();) {
1141: ObjectName currentObjectName = (ObjectName) i.next();
1142: // Check if this ObjectName was already present in oldValueList
1143: int currentObjectNamePosition = oldValues
1144: .indexOf(currentObjectName);
1145: // we have a new Reference
1146: if (currentObjectNamePosition == -1) {
1147: // returns true if we have a new reference, false if the MBean is already referenced
1148: if (addNewMBeanReference(currentObjectName, relationId,
1149: roleName)) {
1150: // add to new references list
1151: newReferenceList.add(currentObjectName);
1152: }
1153: } else {
1154: // MBean referenced in an old value remove
1155: oldValues.remove(currentObjectNamePosition);
1156: }
1157: }
1158: List obsoleteReferenceList = getObsoleteReferenceList(
1159: oldValues, relationId, roleName);
1160: // update listeners as to the new references
1161: updateUnregistrationListener(newReferenceList,
1162: obsoleteReferenceList);
1163: }
1164:
1165: private List getObsoleteReferenceList(List oldValues,
1166: String relationId, String roleName)
1167: throws IllegalArgumentException {
1168: List obsoleteReferenceList = new ArrayList();
1169: for (Iterator i = oldValues.iterator(); i.hasNext();) {
1170: ObjectName currentObjectName = (ObjectName) i.next();
1171: if (removeMBeanReference(currentObjectName, relationId,
1172: roleName)) {
1173: obsoleteReferenceList.add(currentObjectName);
1174: }
1175: }
1176: return obsoleteReferenceList;
1177: }
1178:
1179: private boolean removeMBeanReference(ObjectName objectName,
1180: String relationId, String roleName)
1181: throws IllegalArgumentException {
1182: if (relationId == null)
1183: throw new IllegalArgumentException("Null Relation Id");
1184: if (objectName == null)
1185: throw new IllegalArgumentException("Null ObjectName");
1186: if (roleName == null)
1187: throw new IllegalArgumentException("Null Role Name.");
1188: // first check if we have any references for MBean
1189: HashMap mbeanReferenceMap = (HashMap) getReferencedMBeansFromMap(objectName);
1190:
1191: // no references nothing to remove
1192: if (mbeanReferenceMap == null)
1193: return true;
1194: // we have references get the roleNames for the relationId
1195: ArrayList roleNames = (ArrayList) (mbeanReferenceMap
1196: .get(relationId));
1197:
1198: //check the roleNames is not null before removing
1199: if (roleNames != null) {
1200: // roleName found remove it
1201: if (roleNames.indexOf(roleName) != -1)
1202: roleNames.remove(roleNames.indexOf(roleName));
1203: // no more references remove the relationId key
1204: if (roleNames.isEmpty())
1205: mbeanReferenceMap.remove(relationId);
1206: }
1207: if (mbeanReferenceMap.isEmpty()) {
1208: // now we can remove the MBean ObejctName with all references removed
1209: removeObjectName(objectName);
1210: return true;
1211: }
1212: return false;
1213: }
1214:
1215: private Map getReferencedMBeansFromMap(ObjectName objectName) {
1216: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1217: return ((HashMap) m_referencedMBeanObjectNameToRelationIds
1218: .get(objectName));
1219: }
1220: }
1221:
1222: private boolean addNewMBeanReference(ObjectName objectName,
1223: String relationId, String roleName)
1224: throws IllegalArgumentException {
1225: if (relationId == null)
1226: throw new IllegalArgumentException("Null Relation Id");
1227: if (roleName == null)
1228: throw new IllegalArgumentException("Null Role Name");
1229: if (objectName == null)
1230: throw new IllegalArgumentException("Null ObjectName.");
1231:
1232: // get the ObjectNames of the referenced ObjectName
1233: HashMap mbeanReferenceMap;
1234: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1235: mbeanReferenceMap = ((HashMap) m_referencedMBeanObjectNameToRelationIds
1236: .get(objectName));
1237: }
1238: // it is null, add it to our map and return true - we have a new reference
1239: if (mbeanReferenceMap == null) {
1240: mbeanReferenceMap = new HashMap();
1241: }
1242: List roleNames = (List) mbeanReferenceMap.get(relationId);
1243: if (roleNames == null) {
1244: roleNames = new ArrayList();
1245: roleNames.add(roleName);
1246:
1247: mbeanReferenceMap.put(relationId, roleNames);
1248: addObjectNameToMBeanReference(objectName, mbeanReferenceMap);
1249: return true;
1250: } else {
1251: roleNames.add(roleName);
1252: addObjectNameToMBeanReference(objectName, mbeanReferenceMap);
1253: // not a new MBeanReference return false
1254: return false;
1255: }
1256: }
1257:
1258: private void addObjectNameToMBeanReference(ObjectName objectName,
1259: HashMap mbeanReferenceMap) {
1260: // get the mapfirst, then update it
1261: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1262: Map temp = (Map) m_referencedMBeanObjectNameToRelationIds
1263: .get(objectName);
1264: if (temp != null) {
1265: mbeanReferenceMap.putAll(temp);
1266: }
1267: m_referencedMBeanObjectNameToRelationIds.put(objectName,
1268: mbeanReferenceMap);
1269: }
1270: }
1271:
1272: /**
1273: * <p>Removes given relation from the Relation Service.</p>
1274: * <p>A RelationNotification notification is sent, its type being:
1275: * <ul>
1276: * <li>RelationNotification.RELATION_BASIC_REMOVAL if the relation was only internal to the Relation Service </li>
1277: * <li>RelationNotification.RELATION_MBEAN_REMOVAL if the relation is registered as an MBean</li>
1278: * </ul></p>
1279: * <p>For MBeans referenced in such relation, nothing will be done</p>
1280: *
1281: * @param relationId - relation id of the relation to be removed
1282: * @throws IllegalArgumentException - if null parameter
1283: * @throws RelationServiceNotRegisteredException
1284: * - if the Relation Service is not registered in the MBean Server
1285: * @throws RelationNotFoundException - if no relation corresponding to given relation id
1286: */
1287: public void removeRelation(String relationId)
1288: throws IllegalArgumentException,
1289: RelationServiceNotRegisteredException,
1290: RelationNotFoundException {
1291: isActive();
1292: if (relationId == null)
1293: throw new IllegalArgumentException("Null Relation Id");
1294: Logger logger = getLogger();
1295: if (logger.isEnabledFor(Logger.DEBUG))
1296: logger
1297: .debug("Removing a Relation from the RelationService.");
1298: Object result = getRelationObject(relationId);
1299: if (result instanceof ObjectName) {
1300: // add the objectName to List
1301: List obsoleteReferences = new ArrayList();
1302: obsoleteReferences.add(result);
1303: // update Listener with the list of ObjectNames to be deregistered
1304: updateUnregistrationListener(null, obsoleteReferences);
1305: }
1306: // notify all listeners a relation has been removed
1307: sendRelationRemovalNotification(relationId, null);
1308:
1309: List nonReferencedObjectNameList = getNonReferencedMBeans(relationId);
1310: // remove ObjectNames from global Map
1311: removeNonReferencedMBeans(nonReferencedObjectNameList);
1312: // remove relationId for our nonReferencedMBeans
1313: removeRelationId(relationId);
1314: // we have an MBean remove it from our Map
1315: if (result instanceof ObjectName)
1316: removeRelationMBean((ObjectName) result);
1317: // get the corresponding relationTypeName for the relationId
1318: String relationTypeName = getRelationTypeNameFromMap(relationId);
1319: // remove relationId from our Map
1320: removeRelationIdToRelationTypeName(relationId);
1321: // get all the corresponding relationIds
1322: List relationIdsList = getRelationIds(relationTypeName);
1323:
1324: // we have relationIds for the removed relationTypeName remove them from our Map
1325: if (relationIdsList != null) {
1326: relationIdsList.remove(relationId);
1327: if (relationIdsList.isEmpty()) {
1328: // now we can remove the relationTypeName
1329: removeRelationTypeName(relationTypeName);
1330: }
1331: }
1332: }
1333:
1334: private void removeRelationMBean(ObjectName objectName) {
1335: synchronized (m_relationMBeanObjectNameToRelationId) {
1336: m_relationMBeanObjectNameToRelationId.remove(objectName);
1337: }
1338: }
1339:
1340: private void removeNonReferencedMBeans(List nonReferencedMBeansList) {
1341: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1342: for (Iterator i = nonReferencedMBeansList.iterator(); i
1343: .hasNext();) {
1344: ObjectName currentObjectName = (ObjectName) i.next();
1345: m_referencedMBeanObjectNameToRelationIds
1346: .remove(currentObjectName);
1347: }
1348: }
1349: }
1350:
1351: private List getNonReferencedMBeans(String relationId) {
1352: List referencedMBeanList = new ArrayList();
1353: List nonReferencedObjectNameList = new ArrayList();
1354: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1355: for (Iterator i = (m_referencedMBeanObjectNameToRelationIds
1356: .keySet()).iterator(); i.hasNext();) {
1357: ObjectName currentObjectName = (ObjectName) i.next();
1358: HashMap relationIdMap = (HashMap) (m_referencedMBeanObjectNameToRelationIds
1359: .get(currentObjectName));
1360: if (relationIdMap.containsKey(relationId)) {
1361: relationIdMap.remove(relationId);
1362: referencedMBeanList.add(currentObjectName);
1363: }
1364: if (relationIdMap.isEmpty())
1365: nonReferencedObjectNameList.add(currentObjectName);
1366: }
1367: }
1368: return nonReferencedObjectNameList;
1369: }
1370:
1371: private void removeRelationTypeName(String relationTypeName) {
1372: synchronized (m_relationTypeNameToRelationIds) {
1373: m_relationTypeNameToRelationIds.remove(relationTypeName);
1374: }
1375: }
1376:
1377: private String getRelationTypeNameFromMap(String relationId) {
1378: synchronized (m_relationIdToRelationTypeName) {
1379: return ((String) m_relationIdToRelationTypeName
1380: .get(relationId));
1381: }
1382: }
1383:
1384: private void removeRelationIdToRelationTypeName(String relationId) {
1385: synchronized (m_relationIdToRelationTypeName) {
1386: m_relationIdToRelationTypeName.remove(relationId);
1387: }
1388: }
1389:
1390: private String getMBeanObjectName(ObjectName objectName) {
1391: synchronized (m_relationMBeanObjectNameToRelationId) {
1392: return ((String) m_relationMBeanObjectNameToRelationId
1393: .get(objectName));
1394: }
1395: }
1396:
1397: private void removeRelationId(String relationId) {
1398: synchronized (m_relationIdToRelationObject) {
1399: m_relationIdToRelationObject.remove(relationId);
1400: }
1401: }
1402:
1403: private void updateUnregistrationListener(List newReferenceList,
1404: List obsoleteReferences)
1405: throws RelationServiceNotRegisteredException {
1406: if (newReferenceList != null && obsoleteReferences != null) {
1407: // nothing to do
1408: if (newReferenceList.isEmpty()
1409: && obsoleteReferences.isEmpty())
1410: return;
1411: }
1412: isActive();
1413: if (newReferenceList != null || obsoleteReferences != null) {
1414: boolean isNewListener = false;
1415: if (m_notificationFilter == null) {
1416: m_notificationFilter = new MBeanServerNotificationFilter();
1417: isNewListener = true;
1418: }
1419: synchronized (m_notificationFilter) {
1420: // we have new references - update (Enable in NotificationFilter)
1421: if (newReferenceList != null)
1422: updateNewReferences(newReferenceList);
1423:
1424: // we have obsolete references - update (disable from notificationFilter)
1425: if (obsoleteReferences != null)
1426: updateObsoleteReferences(obsoleteReferences);
1427:
1428: ObjectName mbeanServerDelegateName = null;
1429: try {
1430: mbeanServerDelegateName = new ObjectName(
1431: "JMImplementation:type=MBeanServerDelegate");
1432: } catch (MalformedObjectNameException ignored) {
1433: }
1434:
1435: if (isNewListener) {
1436: try {
1437: m_server.addNotificationListener(
1438: mbeanServerDelegateName, this ,
1439: m_notificationFilter, null);
1440: } catch (InstanceNotFoundException ex) {
1441: throw new RelationServiceNotRegisteredException(
1442: ex.getMessage());
1443: }
1444: }
1445: }
1446: }
1447: }
1448:
1449: private void updateObsoleteReferences(List obsoleteReferences) {
1450: for (Iterator i = obsoleteReferences.iterator(); i.hasNext();) {
1451: ObjectName name = (ObjectName) i.next();
1452: m_notificationFilter.disableObjectName(name);
1453: }
1454: }
1455:
1456: private void updateNewReferences(List newReferencesList) {
1457: for (Iterator i = newReferencesList.iterator(); i.hasNext();) {
1458: ObjectName name = (ObjectName) i.next();
1459: m_notificationFilter.enableObjectName(name);
1460: }
1461: }
1462:
1463: // if null we have an instance of the internalRelation otherwise we have an MBean and can use the proxy
1464: private Relation getRelation(String relationId)
1465: throws RelationNotFoundException {
1466: if (relationId == null)
1467: throw new IllegalArgumentException(
1468: "Null relation id passed into getRelation.");
1469: Relation relation;
1470: // if this is null we have a Relation not an ObjectName so we can return the Relation
1471: if (isRelationMBean(relationId) == null) {
1472: synchronized (m_relationIdToRelationObject) {
1473: relation = (Relation) m_relationIdToRelationObject
1474: .get(relationId);
1475: return relation;
1476: }
1477: }
1478:
1479: final ObjectName relationObjectName = (ObjectName) m_relationIdToRelationObject
1480: .get(relationId);
1481: // oops no relation at all
1482: if (relationObjectName == null) {
1483: throw new RelationNotFoundException(
1484: "Relation not found with ID: " + relationId);
1485: }
1486: // good we have a relation lets return the proxy
1487: m_proxy = (RelationSupportMBean) MBeanServerInvocationHandler
1488: .newProxyInstance(m_server, relationObjectName,
1489: RelationSupportMBean.class, false);
1490: return m_proxy;
1491: }
1492:
1493: // will return an ObjectName or a Relation object
1494: private Object getRelationObject(String relationId)
1495: throws IllegalArgumentException, RelationNotFoundException {
1496: if (relationId == null)
1497: throw new IllegalArgumentException("Null Relation Id");
1498: Object relationObject;
1499: synchronized (m_relationIdToRelationObject) {
1500: relationObject = m_relationIdToRelationObject
1501: .get(relationId);
1502: if (relationObject == null) {
1503: // if this happens is caught by method looking for a null.
1504: throw new RelationNotFoundException("Null Relation");
1505: }
1506: // we return either an ObjectName or an InternalRelation
1507: return relationObject;
1508: }
1509: }
1510:
1511: /**
1512: * <p>Purges the relations</p>
1513: * <p/>
1514: * <p>Depending on the purgeFlag value, this method is either called automatically when a notification is received for the
1515: * 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>
1516: * <p/>
1517: * <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
1518: * unregistered and the purge not done immediately, if the ObjectName is reused and assigned to another MBean referenced in a relation,
1519: * calling manually this purgeRelations() method will cause trouble, as will consider the ObjectName as corresponding to the unregistered MBean,
1520: * not seeing the new one.</p>
1521: * <p/>
1522: * <p/>
1523: * <ul>
1524: * <li>if removing one MBean reference in the role makes its number of references less than the minimum degree, the relation has to be removed.</li>
1525: * <li>if the remaining number of references after removing the MBean reference is still in the cardinality range, keep the relation and update
1526: * it calling its handleMBeanUnregistration() callback.</li>
1527: * </ul></p>
1528: *
1529: * @throws RelationServiceNotRegisteredException
1530: * - if the Relation Service is not registered in the MBean Server.
1531: */
1532: public void purgeRelations()
1533: throws RelationServiceNotRegisteredException {
1534: isActive();
1535: Logger logger = getLogger();
1536: if (logger.isEnabledFor(Logger.DEBUG))
1537: logger.debug("purging relations");
1538:
1539: ArrayList localDeregisteredNotificationList;
1540: synchronized (m_deregisteredNotificationList) {
1541: // cone the list of notifications to be able to recieve notification while processing current ones
1542: localDeregisteredNotificationList = ((ArrayList) ((ArrayList) m_deregisteredNotificationList)
1543: .clone());
1544: // now reset
1545: m_deregisteredNotificationList = new ArrayList();
1546: }
1547:
1548: List obsoleteReferenceList = new ArrayList();
1549: Map localMBeanToRelationId = new HashMap();
1550: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1551: for (Iterator i = localDeregisteredNotificationList
1552: .iterator(); i.hasNext();) {
1553: MBeanServerNotification serverNotification = (MBeanServerNotification) i
1554: .next();
1555: ObjectName deregisteredMBeanName = serverNotification
1556: .getMBeanName();
1557: obsoleteReferenceList.add(deregisteredMBeanName);
1558:
1559: HashMap relationIdMap = (HashMap) m_referencedMBeanObjectNameToRelationIds
1560: .get(deregisteredMBeanName);
1561: localMBeanToRelationId.put(deregisteredMBeanName,
1562: relationIdMap);
1563: m_referencedMBeanObjectNameToRelationIds
1564: .remove(deregisteredMBeanName);
1565: }
1566: }
1567:
1568: // update listener filter to avoid recieving notifications for same MBeans
1569: updateUnregistrationListener(null, obsoleteReferenceList);
1570: for (Iterator i = localDeregisteredNotificationList.iterator(); i
1571: .hasNext();) {
1572: MBeanServerNotification currentNotification = (MBeanServerNotification) i
1573: .next();
1574: ObjectName unregisteredMBeanObjectName = currentNotification
1575: .getMBeanName();
1576: HashMap localRelationIdMap = (HashMap) (localMBeanToRelationId
1577: .get(unregisteredMBeanObjectName));
1578:
1579: Set localRelationIdSet = localRelationIdMap.keySet();
1580: // handles the unregistration of mbeans
1581: unregisterReferences(localRelationIdSet,
1582: localRelationIdMap, unregisteredMBeanObjectName);
1583: }
1584: }
1585:
1586: private void unregisterReferences(Set relationIdSet,
1587: Map relationIdMap, ObjectName objectName)
1588: throws RelationServiceNotRegisteredException {
1589: for (Iterator iter = relationIdSet.iterator(); iter.hasNext();) {
1590: String currentRelationId = (String) iter.next();
1591: ArrayList localRoleNamesList = (ArrayList) (relationIdMap
1592: .get(currentRelationId));
1593: try {
1594: handleReferenceUnregistration(currentRelationId,
1595: objectName, localRoleNamesList);
1596: } catch (RelationTypeNotFoundException ex) {
1597: throw new RuntimeOperationsException(null, ex
1598: .getMessage());
1599: } catch (RelationNotFoundException ex) {
1600: throw new RuntimeOperationsException(null, ex
1601: .getMessage());
1602: } catch (RoleNotFoundException ex) {
1603: throw new RuntimeOperationsException(null, ex
1604: .getMessage());
1605: }
1606: }
1607: }
1608:
1609: private void handleReferenceUnregistration(String relationId,
1610: ObjectName unregisteredObjectName, List roleNames)
1611: throws IllegalArgumentException,
1612: RelationServiceNotRegisteredException,
1613: RelationNotFoundException, RoleNotFoundException,
1614: RelationTypeNotFoundException {
1615: if (relationId == null)
1616: throw new IllegalArgumentException("Null relationId");
1617: if (unregisteredObjectName == null)
1618: throw new IllegalArgumentException("Null ObjectName");
1619: if (roleNames == null)
1620: throw new IllegalArgumentException("Null roleName list");
1621:
1622: isActive();
1623: String relationTypeName = getRelationTypeName(relationId);
1624:
1625: boolean canDeleteRelation = false;
1626: for (Iterator i = roleNames.iterator(); i.hasNext();) {
1627: String currentRoleName = (String) i.next();
1628: int currentRoleCardinality = (getRoleCardinality(
1629: relationId, currentRoleName)).intValue();
1630: int newRoleCardinality = currentRoleCardinality - 1;
1631: RoleInfo currentRoleInfo;
1632: try {
1633: currentRoleInfo = getRoleInfo(relationTypeName,
1634: currentRoleName);
1635: } catch (RelationTypeNotFoundException ex) {
1636: throw new RuntimeOperationsException(null, ex
1637: .getMessage());
1638: } catch (RoleInfoNotFoundException ex) {
1639: throw new RuntimeOperationsException(null, ex
1640: .getMessage());
1641: }
1642: // check that the role cardinality is maintained by the removal
1643: if (!(currentRoleInfo.checkMinDegree(newRoleCardinality))) {
1644: canDeleteRelation = true;
1645: }
1646: }
1647: // roleMinValue been checked everything ok, can now remove the relation
1648: if (canDeleteRelation) {
1649: removeRelation(relationId);
1650: } else {
1651: for (Iterator i = roleNames.iterator(); i.hasNext();) {
1652: String currentRoleName = (String) i.next();
1653: try {
1654: Relation relation = getRelation(relationId);
1655: relation.handleMBeanUnregistration(
1656: unregisteredObjectName, currentRoleName);
1657: } catch (InvalidRoleValueException ex) {
1658: throw new RuntimeOperationsException(null, ex
1659: .getMessage());
1660: }
1661: }
1662: }
1663: }
1664:
1665: private void removeObjectName(ObjectName objectName) {
1666: synchronized (m_referencedMBeanObjectNameToRelationIds) {
1667: m_referencedMBeanObjectNameToRelationIds.remove(objectName);
1668: }
1669: }
1670:
1671: /**
1672: * <p>Retrieves the relations where a given MBean is referenced.</p>
1673: *
1674: * @param mbeanObjectName - ObjectName of MBean
1675: * @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.
1676: * @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.
1677: * @return - HashMap, where the keys are the relation ids of the relations where the MBean is referenced, and the value is, for each key,
1678: * an ArrayList of role names (as an MBean can be referenced in several roles in the same relation).
1679: * @throws IllegalArgumentException - if mbeanObjectName is null
1680: */
1681: public Map findReferencingRelations(ObjectName mbeanObjectName,
1682: String relationTypeName, String roleName)
1683: throws IllegalArgumentException {
1684: if (mbeanObjectName == null)
1685: throw new IllegalArgumentException(
1686: "Cannot find references for a null ObjectName");
1687: Logger logger = getLogger();
1688: if (logger.isEnabledFor(Logger.DEBUG))
1689: logger
1690: .debug("finding referencing relations for MBean with ObjectName: "
1691: + mbeanObjectName.getCanonicalName()
1692: + " and relationTypeName: "
1693: + relationTypeName
1694: + " and roleName: "
1695: + roleName);
1696: HashMap result = new HashMap();
1697: HashMap relationIdMap = (HashMap) getReferencedMBeansFromMap(mbeanObjectName);
1698: if (relationIdMap != null) {
1699: Set allRelationIds = relationIdMap.keySet();
1700: List relationIdList;
1701: if (relationTypeName == null) {
1702: relationIdList = new ArrayList(allRelationIds);
1703: } else {
1704: relationIdList = findReferencesFromIds(allRelationIds,
1705: relationTypeName);
1706: }
1707:
1708: for (Iterator i = relationIdList.iterator(); i.hasNext();) {
1709: String currentRelationId = (String) i.next();
1710: ArrayList currentRoleNameList = (ArrayList) relationIdMap
1711: .get(currentRelationId);
1712: if (roleName == null) {
1713: result.put(currentRelationId, currentRoleNameList
1714: .clone());
1715: } else if (currentRoleNameList.contains(roleName)) {
1716: ArrayList roleNameList = new ArrayList();
1717: roleNameList.add(roleName);
1718: result.put(currentRelationId, roleNameList);
1719: }
1720: }
1721: }
1722: return result;
1723: }
1724:
1725: private ArrayList findReferencesFromIds(Set allRelationIds,
1726: String relationTypeName) {
1727: ArrayList relationIdList = new ArrayList();
1728: for (Iterator i = allRelationIds.iterator(); i.hasNext();) {
1729: String currentRelationId = (String) i.next();
1730: String currentRelationTypeName = getRelationTypeNameFromMap(currentRelationId);
1731: if (currentRelationTypeName.equals(relationTypeName)) {
1732: relationIdList.add(currentRelationId);
1733: }
1734: }
1735: return relationIdList;
1736: }
1737:
1738: /**
1739: * <p>Retrieves the MBeans associated to given one in a relation.</p>
1740: *
1741: * @param mbeanObjectName - ObjectName of MBean
1742: * @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
1743: * @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.
1744: * @return - 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
1745: * relation ids of the relations where the key MBean is associated to given one (as they can be associated in
1746: * several different relations).
1747: * @throws IllegalArgumentException - if mbeanObjectName is null
1748: */
1749: public Map findAssociatedMBeans(ObjectName mbeanObjectName,
1750: String relationTypeName, String roleName)
1751: throws IllegalArgumentException {
1752: if (mbeanObjectName == null)
1753: throw new IllegalArgumentException(
1754: "mbean ObjectName cannot be null.");
1755: Logger logger = getLogger();
1756: if (logger.isEnabledFor(Logger.DEBUG))
1757: logger
1758: .debug("finding associated relations for MBean with ObjectName: "
1759: + mbeanObjectName.getCanonicalName()
1760: + " and relationTypeName: "
1761: + relationTypeName
1762: + " and roleName: "
1763: + roleName);
1764: Map relationIdsToRoleNames = findReferencingRelations(
1765: mbeanObjectName, relationTypeName, roleName);
1766: Map result = new HashMap();
1767: for (Iterator i = (relationIdsToRoleNames.keySet()).iterator(); i
1768: .hasNext();) {
1769: String currentRelationId = (String) i.next();
1770: HashMap objectNamesToRoleMap;
1771: try {
1772: objectNamesToRoleMap = (HashMap) (getReferencedMBeans(currentRelationId));
1773: } catch (RelationNotFoundException ex) {
1774: logger.warn("Relation with ID: " + currentRelationId
1775: + " not found.");
1776: throw new RuntimeOperationsException(null,
1777: "Relation Not Found");
1778: }
1779: for (Iterator iter = (objectNamesToRoleMap.keySet())
1780: .iterator(); iter.hasNext();) {
1781: ObjectName objectName = (ObjectName) iter.next();
1782: if (!(objectName.equals(mbeanObjectName))) {
1783: ArrayList currentRelationIdList = (ArrayList) result
1784: .get(objectName);
1785: if (currentRelationIdList == null) {
1786: currentRelationIdList = new ArrayList();
1787: result.put(objectName, currentRelationIdList);
1788: }
1789: currentRelationIdList.add(currentRelationId);
1790: }
1791: }
1792: }
1793: return result;
1794: }
1795:
1796: /**
1797: * <p>Returns the relation ids for relations of the given type. </p>
1798: *
1799: * @param relationTypeName - relation type name
1800: * @return - arrayList of relationIds
1801: * @throws IllegalArgumentException - if relationTypeName is null
1802: * @throws RelationTypeNotFoundException - if there is no relation type with that name
1803: */
1804: public List findRelationsOfType(String relationTypeName)
1805: throws IllegalArgumentException,
1806: RelationTypeNotFoundException {
1807: if (relationTypeName == null)
1808: throw new IllegalArgumentException(
1809: "relation type name cannot be null.");
1810: Logger logger = getLogger();
1811: if (logger.isEnabledFor(Logger.DEBUG))
1812: logger
1813: .debug("finding relations matching relationTypeName: "
1814: + relationTypeName);
1815:
1816: // throws RelationTypeNotFoundException if not found
1817: getRelationType(relationTypeName);
1818:
1819: List relationIdList = getRelationIds(relationTypeName);
1820: if (relationIdList == null)
1821: return new ArrayList();
1822:
1823: return new ArrayList(relationIdList);
1824: }
1825:
1826: /**
1827: * <P>Retrieves role value for given role name in given relation</p>
1828: *
1829: * @param relationId - the relation identifier
1830: * @param roleName - the name of the role
1831: * @return - an ArrayList of ObjectName objects being the role value
1832: * @throws IllegalArgumentException - if null parameter
1833: * @throws RelationServiceNotRegisteredException
1834: * - if the Relation Service is not registered
1835: * @throws RelationNotFoundException - if no relation with given id
1836: * @throws RoleNotFoundException - if there is no role with given name or
1837: * the role is not readable
1838: */
1839: public List getRole(String relationId, String roleName)
1840: throws IllegalArgumentException,
1841: RelationServiceNotRegisteredException,
1842: RelationNotFoundException, RoleNotFoundException {
1843: isActive();
1844: if (relationId == null)
1845: throw new IllegalArgumentException(
1846: "RelationId cannot have a null value.");
1847: if (roleName == null)
1848: throw new IllegalArgumentException(
1849: "Role Name cannot have a null value.");
1850: Relation relationObject = getRelation(relationId);
1851: return relationObject.getRole(roleName);
1852: }
1853:
1854: /**
1855: * <p>Retrieves values of roles with given names in given relation</p>
1856: *
1857: * @param relationId - the relation identifier
1858: * @param roleNames - array of names of roles to be retrieved
1859: * @return - a RoleResult object, including a RoleList (for roles succcessfully retrieved) and a RoleUnresolvedList (for roles not retrieved).
1860: * @throws IllegalArgumentException - if either parameter is null
1861: * @throws RelationNotFoundException - if no relation with given id
1862: * @throws RelationServiceNotRegisteredException
1863: * - if the Relation Service is not registered in the MBean Server
1864: */
1865: public RoleResult getRoles(String relationId, String[] roleNames)
1866: throws IllegalArgumentException, RelationNotFoundException,
1867: RelationServiceNotRegisteredException {
1868: if (relationId == null)
1869: throw new IllegalArgumentException(
1870: "Illegal Argument relationId is null.");
1871: if (roleNames == null)
1872: throw new IllegalArgumentException(
1873: "Array of Roles Names should not be null");
1874: isActive();
1875: Relation relation = getRelation(relationId);
1876: return relation.getRoles(roleNames);
1877: }
1878:
1879: /**
1880: * <p>Returns all roles present in the relation</p>
1881: *
1882: * @param relationId - the relation identifier
1883: * @return - a RoleResult object, including a RoleList (for roles succcessfully retrieved) and a RoleUnresolvedList (for roles not readable).
1884: * @throws IllegalArgumentException - if the relation id is null
1885: * @throws RelationNotFoundException - if no relation for given id
1886: * @throws RelationServiceNotRegisteredException
1887: * - if the Relation Service is not registered in the MBean Server
1888: */
1889: public RoleResult getAllRoles(String relationId)
1890: throws IllegalArgumentException, RelationNotFoundException,
1891: RelationServiceNotRegisteredException {
1892: if (relationId == null)
1893: throw new IllegalArgumentException(
1894: "RelationId cannot be null");
1895: //Object relationObject = getRelationObject(relationId);
1896: Relation relation = getRelation(relationId);
1897: return relation.getAllRoles();
1898: }
1899:
1900: /**
1901: * <p>Retrieves the number of MBeans currently referenced in the given role.</p>
1902: *
1903: * @param relationId - relation id
1904: * @param roleName - name of role
1905: * @return - the number of currently referenced MBeans in that role
1906: * @throws IllegalArgumentException - if a null parameter
1907: * @throws RelationNotFoundException - if no relation with given id
1908: * @throws RoleNotFoundException - if there is no role with given name
1909: */
1910: public Integer getRoleCardinality(String relationId, String roleName)
1911: throws IllegalArgumentException, RelationNotFoundException,
1912: RoleNotFoundException {
1913: if (relationId == null)
1914: throw new IllegalArgumentException("Relation Id is null.");
1915: if (roleName == null)
1916: throw new IllegalArgumentException("Role Name is null.");
1917: Object relationObject = getRelationObject(relationId);
1918: if (relationObject instanceof InternalRelation)
1919: return (((InternalRelation) relationObject)
1920: .getRoleCardinality(roleName));
1921: else
1922: return m_proxy.getRoleCardinality(roleName);
1923: }
1924:
1925: /**
1926: * <p>Sets the given role in given relation</p>
1927: * <p>Will check the role according to its corresponding role definition provided in relation's relation type </p>
1928: * <p>The Relation Service will keep track of the change to keep the consistency of relations by handling referenced MBean unregistrations</p>
1929: *
1930: * @param relationId - the relation identifier
1931: * @param role - role to be set (name and new value)
1932: * @throws IllegalArgumentException - if null parameter
1933: * @throws RelationServiceNotRegisteredException
1934: * - if relation service is not registered in the MBean Server
1935: * @throws RelationNotFoundException - if no relation with given id
1936: * @throws RoleNotFoundException - if the role does not exist or is not writable
1937: * @throws InvalidRoleValueException - if value provided for role is not valid i.e.
1938: * <ul>
1939: * <li>the number of referenced MBeans in given value is less than expected minimum degree</li>
1940: * <li>the number of referenced MBeans in provided value exceeds expected maximum degree </li>
1941: * <li>one referenced MBean in the value is not an Object of the MBean class expected for that role </li>
1942: * <li>an MBean provided for that role does not exist</li>
1943: * </ul>
1944: */
1945: public void setRole(String relationId, Role role)
1946: throws IllegalArgumentException,
1947: RelationServiceNotRegisteredException,
1948: RelationNotFoundException, RoleNotFoundException,
1949: InvalidRoleValueException {
1950: if (relationId == null)
1951: throw new IllegalArgumentException(
1952: "Illegal Null Relation Id.");
1953: if (role == null)
1954: throw new IllegalArgumentException("Illegal Null Role.");
1955: isActive();
1956: Relation relation = getRelation(relationId);
1957: try {
1958: relation.setRole(role);
1959: } catch (RelationTypeNotFoundException e) {
1960: throw new RelationNotFoundException(
1961: "RelationType not found error: " + e.getMessage());
1962: }
1963: }
1964:
1965: /**
1966: * <p>Sets the given roles in given relation</p>
1967: * <p>Will check the role according to its corresponding role definition provided in relation's relation type </p>
1968: * <p>The Relation Service keeps track of the changes to keep the consistency of relations by handling referenced MBean unregistrations</p>
1969: *
1970: * @param relationId - the relation identifier
1971: * @param roleList - the list of roles to be set
1972: * @return - RoleResult object, including a RoleList(for roles succcessfully set) and a RoleUnresolvedList(for roles not set).
1973: * @throws RelationServiceNotRegisteredException
1974: * - if the realtionService has not been registered in the mbean server
1975: * @throws IllegalArgumentException - if any of the parameters are null
1976: * @throws RelationNotFoundException - if no relation for the given id has been found
1977: */
1978: public RoleResult setRoles(String relationId, RoleList roleList)
1979: throws RelationServiceNotRegisteredException,
1980: IllegalArgumentException, RelationNotFoundException {
1981: if (relationId == null)
1982: throw new IllegalArgumentException("Relation Id is null");
1983: if (roleList == null)
1984: throw new IllegalArgumentException("RoleList is null");
1985: isActive();
1986: Relation relation = getRelation(relationId);
1987: try {
1988: return relation.setRoles(roleList);
1989: } catch (RelationTypeNotFoundException ex) {
1990: throw new RuntimeOperationsException(null,
1991: "Unable to find a RelationTypeName for relation ID: "
1992: + relationId);
1993: }
1994: }
1995:
1996: /**
1997: * <p>Retrieves MBeans referenced in the various roles of the relation</p>
1998: *
1999: * @param relationId - the relation identifier
2000: * @return - a hashMap mapping as key the MBean ObjectName and an arrayList of String roleNames.
2001: * @throws IllegalArgumentException - if relation id is null
2002: * @throws RelationNotFoundException - if no relation for given relation id
2003: */
2004: public Map getReferencedMBeans(String relationId)
2005: throws IllegalArgumentException, RelationNotFoundException {
2006: if (relationId == null)
2007: throw new IllegalArgumentException("Null Relation Id");
2008: Logger logger = getLogger();
2009: if (logger.isEnabledFor(Logger.DEBUG))
2010: logger.debug("getting MBeans referenced for ID: "
2011: + relationId);
2012: Relation relation = getRelation(relationId);
2013: return relation.getReferencedMBeans();
2014: }
2015:
2016: /**
2017: * <p>Returns name of associated relation type for given relation</p>
2018: *
2019: * @param relationId - the relation identifier
2020: * @return - the name of the associated relation type
2021: * @throws IllegalArgumentException - if null parameter
2022: * @throws RelationNotFoundException - if no relation for given relation id
2023: */
2024: public String getRelationTypeName(String relationId)
2025: throws IllegalArgumentException, RelationNotFoundException {
2026: if (relationId == null)
2027: throw new IllegalArgumentException("Null Relation Id");
2028: Logger logger = getLogger();
2029: if (logger.isEnabledFor(Logger.DEBUG))
2030: logger.debug("getting the relationType for ID: "
2031: + relationId);
2032: Relation relation = getRelation(relationId);
2033: return relation.getRelationTypeName();
2034: }
2035:
2036: /**
2037: * <p>Invoked when a JMX notification occurs. Currently handles notifications for unregistration of MBeans,
2038: * either referenced in a relation role or being a relation itself.</p>
2039: *
2040: * @param notification - the notification needs to be of type MBeanServerNotification
2041: * @param handback - An opaque object which helps the listener to associate information regarding the MBean emitter (can be null).
2042: */
2043: public void handleNotification(Notification notification,
2044: Object handback) {
2045: if (notification == null)
2046: throw new IllegalArgumentException("Null Notification");
2047: if (notification instanceof MBeanServerNotification) {
2048: String notificationType = notification.getType();
2049: if (notificationType
2050: .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
2051: ObjectName mbeanName = ((MBeanServerNotification) notification)
2052: .getMBeanName();
2053: // handle unregistration by purging relations
2054: handleUnregistration(notification, mbeanName);
2055: // remove mbeans now
2056: handleMBeanRemoval(mbeanName);
2057: }
2058: }
2059: }
2060:
2061: private void handleMBeanRemoval(ObjectName mbeanName) {
2062: String relationId = getMBeanObjectName(mbeanName);
2063: if (relationId != null) {
2064: try {
2065: // we have a relationId now removeRelation
2066: removeRelation(relationId);
2067: } catch (Exception ex) {
2068: throw new RuntimeOperationsException(null, ex
2069: .getMessage());
2070: }
2071: }
2072: }
2073:
2074: private void handleUnregistration(Notification notification,
2075: ObjectName objectName) {
2076: boolean isReferenced = false;
2077: synchronized (m_referencedMBeanObjectNameToRelationIds) {
2078: // check the mbeanObjectName can be found
2079: if (m_referencedMBeanObjectNameToRelationIds
2080: .containsKey(objectName)) {
2081: // it does so add it to our list of deregistrations
2082: synchronized (m_deregisteredNotificationList) {
2083: m_deregisteredNotificationList.add(notification);
2084: }
2085: isReferenced = true;
2086: }
2087: if (isReferenced && m_purgeFlag) {
2088: try {
2089: // purge the RelationService
2090: purgeRelations();
2091: } catch (Exception ex) {
2092: throw new RuntimeOperationsException(null, ex
2093: .getMessage());
2094: }
2095: }
2096: }
2097: }
2098:
2099: /**
2100: * <p>Returns a NotificationInfo object containing the name of the Java class of the notification and the notification types sent</p>
2101: *
2102: * @return - the array of possible notifications
2103: */
2104: public MBeanNotificationInfo[] getNotificationInfo() {
2105: MBeanNotificationInfo[] notificationInfo = new MBeanNotificationInfo[1];
2106: String[] notificationTypes = new String[6];
2107: notificationTypes[0] = RelationNotification.RELATION_BASIC_CREATION;
2108: notificationTypes[1] = RelationNotification.RELATION_MBEAN_CREATION;
2109: notificationTypes[2] = RelationNotification.RELATION_BASIC_UPDATE;
2110: notificationTypes[3] = RelationNotification.RELATION_MBEAN_UPDATE;
2111: notificationTypes[4] = RelationNotification.RELATION_BASIC_REMOVAL;
2112: notificationTypes[5] = RelationNotification.RELATION_MBEAN_REMOVAL;
2113:
2114: String notificationDescription = "Sent when a relation is created, updated or deleted.";
2115: notificationInfo[0] = new MBeanNotificationInfo(
2116: notificationTypes, "RelationNotification",
2117: notificationDescription);
2118: return notificationInfo;
2119: }
2120:
2121: /**
2122: * <p>Implementation of interface MBeanRegistration @see MBeanRegistration</p>
2123: * <p>Allows the MBean to perform any operations it needs before being registered in the MBean server. If the name of the MBean is
2124: * not specified, the MBean can provide a name for its registration. If any exception is raised, the MBean will not be registered
2125: * in the MBean server.</p>
2126: *
2127: * @param server - The MBean server in which the MBean will be registered
2128: * @param name - The object name of the MBean. This name is null if the name parameter to one of the createMBean or registerMBean
2129: * methods in the @see MBeanServer interface is null. In that case, this method must return a non-null ObjectName for the new MBean.
2130: * @return - The name under which the MBean is to be registered. This value must not be null. If the name parameter is
2131: * not null, it will usually but not necessarily be the returned value
2132: * @throws Exception - This exception will be caught by the MBean server and re-thrown as an
2133: * @see javax.management.MBeanRegistrationException or a @see RuntimeMBeanException.
2134: */
2135: public ObjectName preRegister(MBeanServer server, ObjectName name)
2136: throws Exception {
2137: m_server = server;
2138: m_relationServiceObjectName = name == null ? new ObjectName(
2139: m_server.getDefaultDomain(), "service", "Relation")
2140: : name;
2141: return m_relationServiceObjectName;
2142: }
2143:
2144: /**
2145: * <p>Allows the MBean to perform any operations needed after having been registered in the MBean server or after the registration has failed</p>
2146: *
2147: * @param registrationDone - Indicates whether or not the MBean has been successfully registered in the MBean server.
2148: * The value false means that the registration phase has failed
2149: * @see MBeanRegistration
2150: */
2151: public void postRegister(Boolean registrationDone) {
2152: Logger logger = getLogger();
2153: boolean done = registrationDone.booleanValue();
2154: if (!done) {
2155: m_server = null;
2156: logger.warn("Relation service was NOT registered");
2157: } else {
2158: if (logger.isEnabledFor(Logger.DEBUG)) {
2159: logger.debug("Relation service postRegistered");
2160: }
2161: }
2162: }
2163:
2164: /**
2165: * <p>Allows the MBean to perform any operations it needs before being unregistered by the MBean server.
2166: *
2167: * @throws Exception - This exception will be caught by the MBean server and re-thrown as an
2168: * @see MBeanRegistration </p>
2169: * <p>The impmentation does nothing but log registration of the relation service</p>
2170: * @see javax.management.MBeanRegistrationException or a @see RuntimeMBeanException
2171: */
2172: public void preDeregister() throws Exception {
2173: Logger logger = getLogger();
2174: if (logger.isEnabledFor(Logger.DEBUG)) {
2175: logger.debug("Relation service preDeregistered");
2176: }
2177: }
2178:
2179: /**
2180: * <p> logs nothing but log postRegisration</p>
2181: * <p> Implementation of MBeanRegistration</p>
2182: */
2183: public void postDeregister() {
2184: Logger logger = getLogger();
2185: if (logger.isEnabledFor(Logger.DEBUG)) {
2186: logger.debug("Relation service postDeregistered");
2187: }
2188: }
2189:
2190: static void throwRoleProblemException(int problemType,
2191: String roleName) throws IllegalArgumentException,
2192: RoleNotFoundException, InvalidRoleValueException {
2193: switch (problemType) {
2194: case RoleStatus.NO_ROLE_WITH_NAME:
2195: throw new RoleNotFoundException("RoleName: " + roleName
2196: + " does not exist in the relation");
2197: case RoleStatus.ROLE_NOT_READABLE:
2198: throw new RoleNotFoundException("RoleName: " + roleName
2199: + " is not readable");
2200: case RoleStatus.ROLE_NOT_WRITABLE:
2201: throw new RoleNotFoundException("RoleName: " + roleName
2202: + " is not writable");
2203: case RoleStatus.LESS_THAN_MIN_ROLE_DEGREE:
2204: throw new InvalidRoleValueException("RoleName: " + roleName
2205: + " has references less than the expected minimum.");
2206: case RoleStatus.MORE_THAN_MAX_ROLE_DEGREE:
2207: throw new InvalidRoleValueException("RoleName: " + roleName
2208: + " has references more than the expected maximum.");
2209: case RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS:
2210: throw new InvalidRoleValueException(
2211: "RoleName: "
2212: + roleName
2213: + " has a MBean reference to a MBean not of the expected class of references for that role.");
2214: case RoleStatus.REF_MBEAN_NOT_REGISTERED:
2215: throw new InvalidRoleValueException(
2216: "RoleName: "
2217: + roleName
2218: + " has a reference to null MBean or to a MBean not registered.");
2219: }
2220: }
2221:
2222: private Logger getLogger() {
2223: return Log.getLogger(getClass().getName());
2224: }
2225:
2226: // inner class to represent internal relations defined in the relationService
2227: final class InternalRelation extends RelationSupport {
2228: InternalRelation(String relationId,
2229: ObjectName relationServiceObjectName,
2230: String relationTypeName, RoleList roleList)
2231: throws InvalidRoleValueException,
2232: IllegalArgumentException {
2233: super (relationId, relationServiceObjectName,
2234: relationTypeName, roleList);
2235: }
2236:
2237: // checks role can be read
2238: int getReadingProblemType(Role role, String roleName,
2239: String relationTypeName) {
2240: if (roleName == null)
2241: throw new IllegalArgumentException("Null RoleName");
2242: if (role == null)
2243: return (RoleStatus.NO_ROLE_WITH_NAME);
2244: else {
2245: try {
2246: return ((checkRoleReading(roleName,
2247: relationTypeName)).intValue());
2248: } catch (RelationTypeNotFoundException ex) {
2249: throw new RuntimeOperationsException(null, ex
2250: .getMessage());
2251: }
2252: }
2253: }
2254:
2255: // overridden from RelationSupport
2256: int getRoleWritingValue(Role role, String relationTypeName,
2257: Boolean toBeInitialized)
2258: throws RelationTypeNotFoundException {
2259: try { // check role is writable
2260: return (checkRoleWriting(role, relationTypeName,
2261: toBeInitialized)).intValue();
2262: } catch (RelationTypeNotFoundException ex) {
2263: throw new RuntimeOperationsException(null, ex
2264: .getMessage());
2265: }
2266: }
2267:
2268: // sends role update notification
2269: void sendUpdateRoleNotification(String relationId, Role role,
2270: List oldRoleValue)
2271: throws RelationServiceNotRegisteredException,
2272: RelationNotFoundException {
2273: if (relationId == null)
2274: throw new IllegalArgumentException(
2275: "Null RelationId passed into sendUpdateRoleNotification");
2276: if (role == null)
2277: throw new IllegalArgumentException(
2278: "Null role passed into sendUpdateRoleNotification");
2279: if (oldRoleValue == null)
2280: throw new IllegalArgumentException(
2281: "Null list of role Values passed into sendUpdateRoleNotification");
2282: sendRoleUpdateNotification(relationId, role, oldRoleValue);
2283: }
2284:
2285: void updateRelationServiceMap(String relationId, Role role,
2286: List oldRoleValue) throws IllegalArgumentException,
2287: RelationServiceNotRegisteredException,
2288: RelationNotFoundException {
2289: if (relationId == null)
2290: throw new IllegalArgumentException(
2291: "Null RelationId passed into updateRelationServiceMap");
2292: if (role == null)
2293: throw new IllegalArgumentException(
2294: "Null role passed into updateRelationServiceMap");
2295: if (oldRoleValue == null)
2296: throw new IllegalArgumentException(
2297: "Null list of role Values passed into updateRelationServiceMap");
2298: updateRoleMap(relationId, role, oldRoleValue);
2299: }
2300: }
2301: }
|