/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package javax.management.relation; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.MBeanServerNotification; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; import org.jboss.logging.Logger; import org.jboss.mx.server.MBeanServerImpl; /** * Implements the management interface for a relation service.

* *

Revisions: *

20020311 Adrian Brock: *

*

20020312 Adrian Brock: *

* * @see RelationServiceMBean * * @author Adrian Brock. * @version $Revision: 57200 $ */ public class RelationService extends NotificationBroadcasterSupport implements RelationServiceMBean, MBeanRegistration, NotificationListener { // Constants ----------------------------------------------------- private static final long serialVersionUID = 5434016005679159613L; private static final Logger log = Logger.getLogger(RelationService.class); // Attributes ---------------------------------------------------- /** * Relation ids by relation * Note: A relation is an ObjectName for external relations * and a RelationSupport object for internal relations */ private HashMap idsByRelation = new HashMap(); /** * The relation service object name */ private ObjectName relationService; /** * The notification sequence */ private long notificationSequence = 0; /** * The purge flag */ private boolean purgeFlag; /** * Relations by relation id * Note: A relation is an ObjectName for external relations * and a RelationSupport object for internal relations */ private HashMap relationsById = new HashMap(); /** * The mbean server we are registered with */ private MBeanServer server; /** * The relation types by name */ private HashMap typesByName = new HashMap(); /** * Relation type names by relation ids */ private HashMap typeNamesById = new HashMap(); /** * A notification listener for unregistration */ private MBeanServerNotificationFilter filter; /** * A list of MBeans unregistered but not yet removed. */ private Stack unregistered = new Stack(); /** * Relation ids an MBean is part of by MBean object name * The values side is a HashMap keyed by relation ids * with values of a HashSet of role names. */ private HashMap idRolesMapByMBean = new HashMap(); // The name of the delegate private ObjectName delegate; // Static -------------------------------------------------------- // Constructors -------------------------------------------------- /** * Construct a new relation service * * @param purgeFlag whether immediate purges should be performed, * pass true for immediate, false otherwise */ public RelationService(boolean purgeFlag) { setPurgeFlag(purgeFlag); } // RelationServiceMBean implementation --------------------------- public synchronized void addRelation(ObjectName relation) throws IllegalArgumentException, NoSuchMethodException, RelationServiceNotRegisteredException, InvalidRelationIdException, InvalidRelationServiceException, RelationTypeNotFoundException, InvalidRoleValueException, RoleNotFoundException, InstanceNotFoundException { // Check we have a relation if (relation == null) throw new IllegalArgumentException("null relation"); isActive(); // Get the information we need from the relation ObjectName otherService = null; String relationId = null; String relationTypeName = null; RoleList roleList = null; try { server.isInstanceOf(relation, Relation.class.getName()); otherService = (ObjectName) server.getAttribute(relation, "RelationServiceName"); relationId = (String) server.getAttribute(relation, "RelationId"); relationTypeName = (String) server.getAttribute(relation, "RelationTypeName"); roleList = (RoleList) server.invoke(relation, "retrieveAllRoles", new Object[0], new String[0]); } catch (InstanceNotFoundException e) { throw e; } catch (Exception e) { throw new NoSuchMethodException("Not a relation or not registered"); } if (relationId == null) throw new InvalidRelationIdException("Null relation id"); // Check we are in the correct relation service if (otherService == null || otherService.equals(relationService) == false) throw new InvalidRelationServiceException(otherService + " != " + relationService); // Create a copy of the role list RoleList copy = new RoleList(roleList); // Create any missing roles createMissingRoles(relationTypeName, copy); // Validate the role list RoleValidator.validateRoles(relationService, server, relationTypeName, copy, false); // Add the relation if it is not already present validateAndAddRelation(relationId, relation, relationTypeName); // Monitor this relation filter.enableObjectName(relation); } public synchronized void addRelationType(RelationType relationType) throws IllegalArgumentException, InvalidRelationTypeException { if (relationType == null) throw new IllegalArgumentException("null relation type"); synchronized (typesByName) { String name = relationType.getRelationTypeName(); if (name == null) throw new IllegalArgumentException("Null relation type name in relation type"); if (typesByName.containsKey(name)) throw new InvalidRelationTypeException("duplicate relation id: " + name); validateRelationType(relationType); typesByName.put(name, relationType); } } public Integer checkRoleReading(String roleName, String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (roleName == null) throw new IllegalArgumentException("Null role name"); // Get the relation type RelationType relationType = retrieveRelationTypeForName(relationTypeName); // Get the role information RoleInfo roleInfo = null; try { roleInfo = relationType.getRoleInfo(roleName); } catch (RoleInfoNotFoundException e) { return new Integer(RoleStatus.NO_ROLE_WITH_NAME); } // Is it readable? if (roleInfo.isReadable() == false) return new Integer(RoleStatus.ROLE_NOT_READABLE); // Yes it is return new Integer(0); } public Integer checkRoleWriting(Role role, String relationTypeName, Boolean initFlag) throws IllegalArgumentException, RelationTypeNotFoundException { if (role == null) throw new IllegalArgumentException("Null role name"); if (initFlag == null) throw new IllegalArgumentException("Null init flag"); // Get the relation type RelationType relationType = retrieveRelationTypeForName(relationTypeName); // Get the role information RoleInfo roleInfo = null; try { roleInfo = relationType.getRoleInfo(role.getRoleName()); } catch (RoleInfoNotFoundException e) { return new Integer(RoleStatus.NO_ROLE_WITH_NAME); } // Is it writable? if (initFlag.booleanValue() == false && roleInfo.isWritable() == false) return new Integer(RoleStatus.ROLE_NOT_WRITABLE); // Check the cardinality of the role ArrayList mbeans = (ArrayList) role.getRoleValue(); int beanCount = mbeans.size(); int minimum = roleInfo.getMinDegree(); if (minimum != RoleInfo.ROLE_CARDINALITY_INFINITY && minimum > beanCount) return new Integer(RoleStatus.LESS_THAN_MIN_ROLE_DEGREE); int maximum = roleInfo.getMaxDegree(); if (maximum != RoleInfo.ROLE_CARDINALITY_INFINITY && maximum < beanCount) return new Integer(RoleStatus.MORE_THAN_MAX_ROLE_DEGREE); // Check the MBeans String className = roleInfo.getRefMBeanClassName(); Iterator iterator = mbeans.iterator(); while (iterator.hasNext()) { try { ObjectName objectName = (ObjectName) iterator.next(); if (server.isInstanceOf(objectName, className) == false) return new Integer(RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS); } catch (Exception e) { return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED); } } // Yes it is return new Integer(0); } public synchronized void createRelation(String relationId, String relationTypeName, RoleList roleList) throws IllegalArgumentException, RelationServiceNotRegisteredException, InvalidRelationIdException, RelationTypeNotFoundException, InvalidRoleValueException, RoleNotFoundException { // Take a copy of the role list RoleList copy = null; if (roleList != null) copy = new RoleList(roleList); else copy = new RoleList(); // Create a relation isActive(); RelationSupport relation = new RelationSupport(relationId, relationService, server, relationTypeName, copy); // Create any missing roles createMissingRoles(relationTypeName, copy); // Validate the role list RoleValidator.validateRoles(relationService, server, relationTypeName, copy, false); // Add the relation if it is not already present validateAndAddRelation(relationId, relation, relationTypeName); } public synchronized void createRelationType(String relationTypeName, RoleInfo[] roleInfos) throws IllegalArgumentException, InvalidRelationTypeException { if (relationTypeName == null) throw new IllegalArgumentException("null relation type name"); synchronized (typesByName) { if (typesByName.containsKey(relationTypeName)) throw new InvalidRelationTypeException("duplicate relation id: " + relationTypeName); RelationType relationType = new RelationTypeSupport(relationTypeName, roleInfos); typesByName.put(relationTypeName, relationType); } } public Map findAssociatedMBeans(ObjectName mbeanName, String relationTypeName, String roleName) throws IllegalArgumentException { HashMap referencing = (HashMap) findReferencingRelations(mbeanName, relationTypeName, roleName); HashMap result = new HashMap(); // Loop through our relations Iterator relationIterator = referencing.entrySet().iterator(); while (relationIterator.hasNext()) { Map.Entry referencingEntry = (Map.Entry) relationIterator.next(); String relationId = (String) referencingEntry.getKey(); // Get the all beans in this relation HashMap referenced = null; try { referenced = (HashMap) getReferencedMBeans(relationId); } catch (RelationNotFoundException e) { throw new RuntimeException(e.toString()); } // Check each bean's roles Iterator mbeanIterator = referenced.entrySet().iterator(); while (mbeanIterator.hasNext()) { Map.Entry referencedEntry = (Map.Entry) mbeanIterator.next(); ObjectName objectName = (ObjectName) referencedEntry.getKey(); // Exclude ourselves from the test if (objectName.equals(mbeanName) == false) { // Ok this is one of our associated mbeans ArrayList resultList = (ArrayList) result.get(objectName); if (resultList == null) { resultList = new ArrayList(); resultList.add(relationId); result.put(objectName, resultList); } else if (resultList.contains(relationId) == false) resultList.add(relationId); } } } // All done return result; } public Map findReferencingRelations(ObjectName mbeanName, String relationTypeName, String roleName) throws IllegalArgumentException { if (mbeanName == null) throw new IllegalArgumentException("null object name"); HashMap result = new HashMap(); // Get the relations to roles map for the passed mbean HashMap idRolesMap = (HashMap) idRolesMapByMBean.get(mbeanName); if (idRolesMap == null) return result; Iterator iterator = idRolesMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); String relationId = (String) entry.getKey(); HashSet roleNames = (HashSet) entry.getValue(); // See if we have the correct relation type if (relationTypeName == null || typeNamesById.get(relationId).equals(relationTypeName)) { ArrayList resultRoleNames = new ArrayList(); // No role specified, add them all if (roleName == null) resultRoleNames.addAll(roleNames); // See if we have this role else if (roleNames.contains(roleName) && resultRoleNames.contains(roleName) == false) resultRoleNames.add(roleName); // Did we find anything, use it if (resultRoleNames.size() > 0) result.put(relationId, resultRoleNames); } } // All done return result; } public List findRelationsOfType(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (relationTypeName == null) throw new IllegalArgumentException("null relation type name"); if (typesByName.containsKey(relationTypeName) == false) throw new RelationTypeNotFoundException("relation type name not found"); // Build the list ArrayList result = new ArrayList(); Iterator iterator = typeNamesById.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); String typeName = (String) entry.getValue(); if (typeName.equals(relationTypeName)) result.add(entry.getKey()); } // All done return result; } public List getAllRelationIds() { ArrayList result = new ArrayList(relationsById.size()); synchronized (relationsById) { Iterator iterator = relationsById.keySet().iterator(); while (iterator.hasNext()) result.add(iterator.next()); } return result; } public List getAllRelationTypeNames() { ArrayList result = new ArrayList(typesByName.size()); synchronized (typesByName) { Iterator iterator = typesByName.keySet().iterator(); while (iterator.hasNext()) result.add(iterator.next()); } return result; } public RoleResult getAllRoles(String relationId) throws IllegalArgumentException, RelationNotFoundException, RelationServiceNotRegisteredException { isActive(); Object relation = retrieveRelationForId(relationId); // Ask the relation for the roles if (relation instanceof RelationSupport) { return ((RelationSupport) relation).getAllRoles(); } else { ObjectName objectName = (ObjectName) relation; try { return (RoleResult) server.getAttribute(objectName, "AllRoles"); } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (Exception e) { throw new RuntimeException(e.toString()); } } } public boolean getPurgeFlag() { return purgeFlag; } public Map getReferencedMBeans(String relationId) throws IllegalArgumentException, RelationNotFoundException { Object relation = retrieveRelationForId(relationId); // Ask the relation for the referenced mbeans if (relation instanceof RelationSupport) { return ((RelationSupport) relation).getReferencedMBeans(); } else { ObjectName objectName = (ObjectName) relation; try { return (Map) server.getAttribute(objectName, "ReferencedMBeans"); } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (Exception e) { throw new RuntimeException(e.toString()); } } } public String getRelationTypeName(String relationId) throws IllegalArgumentException, RelationNotFoundException { return retrieveTypeNameForId(relationId); } public List getRole(String relationId, String roleName) throws IllegalArgumentException, RelationNotFoundException, RelationServiceNotRegisteredException, RoleNotFoundException { // Get the relation object name if (roleName == null) throw new IllegalArgumentException("null role"); isActive(); Object relation = retrieveRelationForId(relationId); // Ask the relation for the role value if (relation instanceof RelationSupport) { return ((RelationSupport) relation).getRole(roleName); } else { ObjectName objectName = (ObjectName) relation; try { List result = (List) server.invoke(objectName, "getRole", new Object[]{roleName}, new String[]{"java.lang.String"}); return result; } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (MBeanException mbe) { Exception e = mbe.getTargetException(); if (e instanceof RoleNotFoundException) throw (RoleNotFoundException) e; else throw new RuntimeException(e.toString()); } catch (ReflectionException e) { throw new RuntimeException(e.toString()); } } } public Integer getRoleCardinality(String relationId, String roleName) throws IllegalArgumentException, RelationNotFoundException, RoleNotFoundException { // Get the relation object name if (roleName == null) throw new IllegalArgumentException("null role"); Object relation = retrieveRelationForId(relationId); // Ask the relation for the role cardinality if (relation instanceof RelationSupport) { return ((RelationSupport) relation).getRoleCardinality(roleName); } else { ObjectName objectName = (ObjectName) relation; try { Integer result = (Integer) server.invoke( objectName, "getRoleCardinality", new Object[]{roleName}, new String[]{"java.lang.String"}); return result; } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (MBeanException mbe) { Exception e = mbe.getTargetException(); if (e instanceof RoleNotFoundException) throw (RoleNotFoundException) e; else throw new RuntimeException(e.toString()); } catch (ReflectionException e) { throw new RuntimeException(e.toString()); } } } public RoleInfo getRoleInfo(String relationTypeName, String roleInfoName) throws IllegalArgumentException, RelationTypeNotFoundException, RoleInfoNotFoundException { // Get the relation type RelationType relationType = retrieveRelationTypeForName(relationTypeName); // Return the role information return relationType.getRoleInfo(roleInfoName); } public List getRoleInfos(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { // Get the relation type RelationType relationType = retrieveRelationTypeForName(relationTypeName); // Return the role information return relationType.getRoleInfos(); } public RoleResult getRoles(String relationId, String[] roleNames) throws IllegalArgumentException, RelationNotFoundException, RelationServiceNotRegisteredException { // Get the relation object name if (roleNames == null) throw new IllegalArgumentException("null role names"); isActive(); Object relation = retrieveRelationForId(relationId); // Ask the relation for the role value if (relation instanceof RelationSupport) { return ((RelationSupport) relation).getRoles(roleNames); } else { ObjectName objectName = (ObjectName) relation; try { RoleResult result = (RoleResult) server.invoke(objectName, "getRoles", new Object[]{roleNames}, new String[]{new String[0].getClass().getName()}); return result; } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (MBeanException e) { throw new RuntimeException(e.toString()); } catch (ReflectionException e) { throw new RuntimeException(e.toString()); } } } public Boolean hasRelation(String relationId) throws IllegalArgumentException { if (relationId == null) throw new IllegalArgumentException("null relation id"); return new Boolean(relationsById.get(relationId) != null); } public void isActive() throws RelationServiceNotRegisteredException { if (server == null) throw new RelationServiceNotRegisteredException("Not registered"); } public String isRelation(ObjectName objectName) throws IllegalArgumentException { if (objectName == null) throw new IllegalArgumentException("null object name"); return (String) idsByRelation.get(objectName); } public ObjectName isRelationMBean(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) throw new IllegalArgumentException("null relation id"); Object result = relationsById.get(relationId); if (result == null) throw new RelationNotFoundException(relationId); if (result instanceof ObjectName) return (ObjectName) result; else return null; } public void purgeRelations() throws RelationServiceNotRegisteredException { isActive(); // Keep going until they are all done while (unregistered.empty() == false) { // Get the next object ObjectName mbean = (ObjectName) unregistered.pop(); // Keep track of the remain relations/roles HashMap relationRoles = new HashMap(); // Get the relations for this mbean HashMap idRolesMap = (HashMap) idRolesMapByMBean.get(mbean); // Go through each relation/role Iterator iterator = idRolesMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); String relationId = (String) entry.getKey(); HashSet roleNames = (HashSet) entry.getValue(); Iterator inner = roleNames.iterator(); while (inner.hasNext()) { String roleName = (String) inner.next(); relationRoles.put(relationId, roleName); } } // Tell the relation about the removed role iterator = relationRoles.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); String relationId = (String) entry.getKey(); String roleName = (String) entry.getValue(); Object relation = relationsById.get(relationId); String typeName = (String) typeNamesById.get(relationId); RelationType relationType = (RelationType) typesByName.get(typeName); if (relation instanceof RelationSupport) { RelationSupport support = (RelationSupport) relation; try { // Check to see if the relation is now invalid Integer cardinality = support.getRoleCardinality(roleName); RoleInfo roleInfo = relationType.getRoleInfo(roleName); int minDegree = roleInfo.getMinDegree(); // It's invalid, remove it if (cardinality.intValue() == minDegree) removeRelation(relationId); else // It's ok tell the relation about the unregistration support.handleMBeanUnregistration(mbean, roleName); } catch (Exception e) { log.debug("Error during purge", e); } } else { try { // Check to see if the relation is now invalid ObjectName objectName = (ObjectName) relation; Integer cardinality = (Integer) server.invoke( objectName, "getRoleCardinality", new Object[]{roleName}, new String[]{"java.lang.String"}); RoleInfo roleInfo = relationType.getRoleInfo(roleName); int minDegree = roleInfo.getMinDegree(); // It's invalid, remove it if (cardinality.intValue() == minDegree) removeRelation(relationId); else // It's ok tell the relation about the unregistration server.invoke(objectName, "handleMBeanUnregistration", new Object[]{mbean, roleName}, new String[]{"java.lang.String", "java.lang.String "}); } catch (MBeanException mbe) { log.debug("Error during purge", mbe.getTargetException()); } catch (Exception e) { log.debug("Error during purge", e); } } } } } public synchronized void removeRelation(String relationId) throws IllegalArgumentException, RelationNotFoundException, RelationServiceNotRegisteredException { isActive(); // Get the MBeans that are part of this relation ArrayList unregMBeans = new ArrayList( getReferencedMBeans(relationId).keySet()); // Check to see whether this will remove the MBean Iterator iterator = unregMBeans.iterator(); while (iterator.hasNext()) { // Remove the MBeans relation role map ObjectName mbean = (ObjectName) iterator.next(); HashMap idRolesMap = (HashMap) idRolesMapByMBean.get(mbean); idRolesMap.remove(relationId); // We were the last? if (idRolesMap.size() == 0) idRolesMapByMBean.remove(mbean); // Is this an MBean a relation? if (idsByRelation.containsKey(mbean) == false) iterator.remove(); } // Send a notification of the removal sendRelationRemovalNotification(relationId, unregMBeans); // Remove the relation from all the data structures Object relation = retrieveRelationForId(relationId); relationsById.remove(relationId); idsByRelation.remove(relation); typeNamesById.remove(relationId); // Update the relation management flag if (relation instanceof ObjectName) { try { Attribute attribute = new Attribute("RelationServiceManagementFlag", new Boolean(false)); server.setAttribute((ObjectName) relation, attribute); } catch (Exception doesntImplementRelationSupportMBean) { } // Don't monitor this relation anymore filter.disableObjectName((ObjectName) relation); } } public synchronized void removeRelationType(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException, RelationServiceNotRegisteredException { if (relationTypeName == null) throw new IllegalArgumentException("null relation type name"); isActive(); if (typesByName.containsKey(relationTypeName) == false) throw new RelationTypeNotFoundException("relation type name not found"); // Remove any relations for this relation type // FIXME: This is rubbish ArrayList ids = new ArrayList(); Map.Entry entry; Iterator iterator = typeNamesById.entrySet().iterator(); while (iterator.hasNext()) { entry = (Map.Entry) iterator.next(); if (entry.getValue().equals(relationTypeName)) ids.add(entry.getKey()); } iterator = ids.iterator(); while (iterator.hasNext()) { try { removeRelation((String) iterator.next()); } catch (RelationNotFoundException ignored) { } } // Remove the relation type typesByName.remove(relationTypeName); } public void sendRelationCreationNotification(String relationId) throws IllegalArgumentException, RelationNotFoundException { // Determine the type of relation String type = null; String description = null; if (relationsById.get(relationId) instanceof RelationSupport) { type = RelationNotification.RELATION_BASIC_CREATION; description = "Creation of internal relation."; } else { type = RelationNotification.RELATION_MBEAN_CREATION; description = "Creation of external relation."; } // Send the notification sendNotification(type, description, relationId, null, null, null); } public void sendRelationRemovalNotification(String relationId, List unregMBeans) throws IllegalArgumentException, RelationNotFoundException { // Determine the type of relation String type = null; String description = null; if (relationsById.get(relationId) instanceof RelationSupport) { type = RelationNotification.RELATION_BASIC_REMOVAL; description = "Removal of internal relation."; } else { type = RelationNotification.RELATION_MBEAN_REMOVAL; description = "Removal of external relation."; } // Send the notification sendNotification(type, description, relationId, unregMBeans, null, null); } public void sendRoleUpdateNotification(String relationId, Role newRole, List oldRoleValue) throws IllegalArgumentException, RelationNotFoundException { // Determine the type of relation String type = null; String description = null; if (relationsById.get(relationId) instanceof RelationSupport) { type = RelationNotification.RELATION_BASIC_UPDATE; description = "Update of internal relation."; } else { type = RelationNotification.RELATION_MBEAN_UPDATE; description = "Update of external relation."; } if (newRole == null) throw new IllegalArgumentException("null role"); if (oldRoleValue == null) throw new IllegalArgumentException("null old role value"); // Send the notification sendNotification(type, description, relationId, null, newRole, oldRoleValue); } public void setPurgeFlag(boolean value) { purgeFlag = value; } public void setRole(String relationId, Role role) throws RelationServiceNotRegisteredException, IllegalArgumentException, RelationNotFoundException, RoleNotFoundException, InvalidRoleValueException { // Get the relation object name if (role == null) throw new IllegalArgumentException("null role"); isActive(); Object relation = retrieveRelationForId(relationId); // Ask the relation to set the role if (relation instanceof RelationSupport) { try { ((RelationSupport) relation).setRole(role); } catch(RelationTypeNotFoundException e) { RelationNotFoundException rnfe = new RelationNotFoundException(e.getMessage()); rnfe.initCause(e); throw rnfe; } } else { ObjectName objectName = (ObjectName) relation; try { server.setAttribute(objectName, new Attribute("Role", role)); } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (MBeanException mbe) { Exception e = mbe.getTargetException(); if (e instanceof RoleNotFoundException) throw (RoleNotFoundException) e; else if (e instanceof InvalidRoleValueException) throw (InvalidRoleValueException) e; else throw new RuntimeException(e.toString()); } catch (AttributeNotFoundException e) { throw new RuntimeException(e.toString()); } catch (InvalidAttributeValueException e) { throw new RuntimeException(e.toString()); } catch (ReflectionException e) { throw new RuntimeException(e.toString()); } } } public RoleResult setRoles(String relationId, RoleList roles) throws IllegalArgumentException, RelationServiceNotRegisteredException, RelationNotFoundException { // Get the relation object name if (roles == null) throw new IllegalArgumentException("null roles"); isActive(); Object relation = retrieveRelationForId(relationId); // Ask the relation to set the roles if (relation instanceof RelationSupport) { try { return ((RelationSupport) relation).setRoles(roles); } // Why doesn't it throw this? catch (RelationTypeNotFoundException e) { throw new RuntimeException(e.toString()); } } else { ObjectName objectName = (ObjectName) relation; try { RoleResult result = (RoleResult) server.invoke(objectName, "setRoles", new Object[]{roles}, new String[]{"javax.management.relation.RoleList"}); return result; } catch (InstanceNotFoundException e) { throw new RelationNotFoundException(objectName.toString()); } catch (MBeanException e) { throw new RuntimeException(e.getTargetException().toString()); } catch (ReflectionException e) { throw new RuntimeException(e.toString()); } } } public void updateRoleMap(String relationId, Role newRole, List oldRoleValue) throws IllegalArgumentException, RelationServiceNotRegisteredException, RelationNotFoundException { if (relationId == null) throw new IllegalArgumentException("null relation id"); if (newRole == null) throw new IllegalArgumentException("null role"); if (oldRoleValue == null) throw new IllegalArgumentException("null old role value"); isActive(); if (relationsById.containsKey(relationId) == false) throw new RelationNotFoundException("Invalid relation id: " + relationId); // Get the role name and new Value String roleName = newRole.getRoleName(); ArrayList newRoleValue = (ArrayList) newRole.getRoleValue(); // Remove the unused and unchanged object names Iterator iterator = oldRoleValue.iterator(); while (iterator.hasNext()) { ObjectName objectName = (ObjectName) iterator.next(); if (newRoleValue.contains(objectName) == false) { // We have to remove this relation/role HashMap idRolesMap = (HashMap) idRolesMapByMBean.get(objectName); HashSet roleNames = (HashSet) idRolesMap.get(relationId); roleNames.remove(roleName); if (roleNames.size() == 0) { idRolesMap.remove(relationId); if (idRolesMap.size() == 0) { idRolesMapByMBean.remove(objectName); filter.disableObjectName(objectName); } } } } // Make sure all the roles exist iterator = newRoleValue.iterator(); while (iterator.hasNext()) { ObjectName objectName = (ObjectName) iterator.next(); HashMap idRolesMap = (HashMap) idRolesMapByMBean.get(objectName); if (idRolesMap == null) { idRolesMap = new HashMap(); idRolesMapByMBean.put(objectName, idRolesMap); filter.enableObjectName(objectName); } HashSet roleNames = (HashSet) idRolesMap.get(relationId); if (roleNames == null) { roleNames = new HashSet(); idRolesMap.put(relationId, roleNames); } if (roleNames.contains(roleName) == false) roleNames.add(roleName); } } // MBeanRegistration implementation ------------------------------ public ObjectName preRegister(MBeanServer server, ObjectName objectName) throws Exception { // Save some data this.server = server; this.relationService = objectName; // Install our notification listener we aren't interested in registration // We aren't monitoring anything at start-up filter = new MBeanServerNotificationFilter(); filter.enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION); filter.disableAllObjectNames(); delegate = new ObjectName(MBeanServerImpl.MBEAN_SERVER_DELEGATE); server.addNotificationListener(delegate, this, filter, null); // Ok go ahead and register return objectName; } public void postRegister(Boolean registered) { } public void preDeregister() throws Exception { } public void postDeregister() { try { // Remove the notification listener server.removeNotificationListener(delegate, this); } catch (Exception ignored) { } // REVIEW: Should we remove relation types/relations here? // We are no longer registered server = null; } // NotificationListener implementation ---------------------------- public void handleNotification(Notification notification, Object handback) { // Make sure we are not called malicously if (notification == null || !(notification instanceof MBeanServerNotification)) return; // It still might be malicous MBeanServerNotification mbsn = (MBeanServerNotification) notification; if (mbsn.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION) == false) return; // Add the object to the list of mbeans to remove ObjectName objectName = mbsn.getMBeanName(); unregistered.push(objectName); try { // Are we set to automatic purge? if (purgeFlag == true) purgeRelations(); } catch (Exception ignored) { } try { // Is this a relation? String relationId = (String) idsByRelation.get(objectName); if (relationId != null) removeRelation(relationId); } catch (Exception ignored) { } } // NotificationBroadcasterSupport overrides ----------------------- public MBeanNotificationInfo[] getNotificationInfo() { MBeanNotificationInfo[] result = new MBeanNotificationInfo[1]; String[] types = new String[] { RelationNotification.RELATION_BASIC_CREATION, RelationNotification.RELATION_BASIC_REMOVAL, RelationNotification.RELATION_BASIC_UPDATE, RelationNotification.RELATION_MBEAN_CREATION, RelationNotification.RELATION_MBEAN_REMOVAL, RelationNotification.RELATION_MBEAN_UPDATE }; result[0] = new MBeanNotificationInfo(types, "javax.management.relation.RelationNotification", "Notifications sent by the Relation Service MBean"); return result; } // Private -------------------------------------------------------- /** * Create missing roles * * @param relationTypeName the relation type name * @param roleList the existing roles * @exception RelationTypeNotFoundException for a missing relation type */ private void createMissingRoles(String relationTypeName, RoleList roleList) throws RelationTypeNotFoundException { if (relationTypeName == null) throw new RelationTypeNotFoundException("RelationType name null not found"); // Get the relation type RelationType relationType = retrieveRelationTypeForName(relationTypeName); // Get the Role Information ArrayList roleInfos = (ArrayList) relationType.getRoleInfos(); // Add empty roles for missing roles Iterator iterator = roleInfos.iterator(); while (iterator.hasNext()) { RoleInfo roleInfo = (RoleInfo) iterator.next(); boolean found = false; Iterator inner = roleList.iterator(); while (inner.hasNext()) { Role role = (Role) inner.next(); if (role.getRoleName().equals(roleInfo.getName())) { found = true; break; } } if (found == false) roleList.add(new Role(roleInfo.getName(), new RoleList())); } } /** * Get the relation for a relation id * * @param relationId the relation id * @return the relation's object name or a relation support object * @exception IllegalArgumentException for a null relation id * @exception RelationNotFoundException when the relation is not registered */ private Object retrieveRelationForId(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) throw new IllegalArgumentException("null relation id"); Object result = relationsById.get(relationId); if (result == null) throw new RelationNotFoundException(relationId); return result; } /** * Get the relation type name for a relation id * * @param relationId the relation id * @return the relation type name * @exception IllegalArgumentException for a null relation id * @exception RelationNotFoundException when the relation is not registered */ private String retrieveTypeNameForId(String relationId) throws IllegalArgumentException, RelationNotFoundException { if (relationId == null) throw new IllegalArgumentException("null relation id"); String result = (String) typeNamesById.get(relationId); if (result == null) throw new RelationNotFoundException(relationId); return result; } /** * Get the relation type for a relation type name * * @param relationTypeName the relation type name * @return the relation type * @exception IllegalArgumentException for a null relation type name * @exception RelationTypeNotFoundException when the relation is not * registered. */ private RelationType retrieveRelationTypeForName(String relationTypeName) throws IllegalArgumentException, RelationTypeNotFoundException { if (relationTypeName == null) throw new IllegalArgumentException("Null relation type name"); // Get the relation type RelationType result = (RelationType) typesByName.get(relationTypeName); if (result == null) throw new RelationTypeNotFoundException(relationTypeName); return result; } /** * Send a notification. * * @param type the notification type * @param description the human readable description * @param relationId the relation id of the relation * @param unregMBeans the mbeans removed when a relation is removed * @param newRole the role after an update * @param oldRoleValue the old role values after an update * @exception IllegalArgumentException for a null relation id * @exception RelationNotFoundException for an invalid relation id. */ private void sendNotification(String type, String description, String relationId, List unregMBeans, Role newRole, List oldRoleValue) throws IllegalArgumentException, RelationNotFoundException { if (type == null) throw new IllegalArgumentException("null notification type"); // Get the relation type name String typeName = retrieveTypeNameForId(relationId); // Get the relation's object name (if it has one) Object relation = retrieveRelationForId(relationId); ObjectName relationName = null; if (relation instanceof ObjectName) relationName = (ObjectName) relation; // Get the next sequence number long sequence; synchronized (this) { sequence = ++notificationSequence; } // Send the notification // REVIEW: According to the spec, the source should be a RelationService // that doesn't make any sense, it's not serializable // I use the object name if (type.equals(RelationNotification.RELATION_BASIC_UPDATE) || type.equals(RelationNotification.RELATION_MBEAN_UPDATE)) sendNotification(new RelationNotification(type, relationService, sequence, System.currentTimeMillis(), description, relationId, typeName, relationName, newRole.getRoleName(), newRole.getRoleValue(), oldRoleValue)); else sendNotification(new RelationNotification(type, relationService, sequence, System.currentTimeMillis(), description, relationId, typeName, relationName, unregMBeans)); } /** * Validate and add the relation. * * @param relationId the relation id * @param relation the relation to add * @param relationTypeName the relation type name * @exception InvalidRelationIdException when it is already present * @exception RelationNotFoundException when an error occurs invoking the * relation * @exception IllegalArgumentException when there is an error in the * parameters * @exception RelationServiceNotRegisteredException when the relation * service has not started. */ private synchronized void validateAndAddRelation(String relationId, Object relation, String relationTypeName) throws InvalidRelationIdException { if (relationsById.containsKey(relationId)) throw new InvalidRelationIdException(relationId); relationsById.put(relationId, relation); idsByRelation.put(relation, relationId); typeNamesById.put(relationId, relationTypeName); // Retrieve all the roles RoleList roles = null; if (relation instanceof RelationSupport) { RelationSupport support = (RelationSupport) relation; roles = support.retrieveAllRoles(); } else { try { roles = (RoleList) server.invoke((ObjectName) relation, "retrieveAllRoles", new Object[0], new String[0]); } catch (Exception e) { throw new RuntimeException(e.toString()); } } // Update the roles Iterator iterator = roles.iterator(); while (iterator.hasNext()) { Role role = (Role) iterator.next(); try { updateRoleMap(relationId, role, role.getRoleValue()); } catch (Exception e) { throw new RuntimeException(e.toString()); } } // We are now managing this relation if (relation instanceof RelationSupport) { RelationSupport support = (RelationSupport) relation; support.setRelationServiceManagementFlag(new Boolean(true)); } else { try { Attribute attribute = new Attribute("RelationServiceManagementFlag", new Boolean(true)); server.setAttribute((ObjectName) relation, attribute); } catch (Exception doesntImplementRelationSupportMBean) { } } // Send a notification of the addition try { sendRelationCreationNotification(relationId); } catch (RelationNotFoundException e) { throw new RuntimeException(e.toString()); } } /** * Validate a relation type. * * @param relationType the relation to validate * @exception InvalidRelationTypeException when it is not valid */ private void validateRelationType(RelationType relationType) throws InvalidRelationTypeException { // Check the role information HashSet roleNames = new HashSet(); ArrayList roleInfos = (ArrayList) relationType.getRoleInfos(); if (roleInfos == null) throw new InvalidRelationTypeException("Null role infos"); if (roleInfos.size() == 0) throw new InvalidRelationTypeException("No role infos"); synchronized (roleInfos) { Iterator iterator = roleInfos.iterator(); while (iterator.hasNext()) { RoleInfo roleInfo = (RoleInfo) iterator.next(); if (roleInfo == null) throw new InvalidRelationTypeException("Null role"); if (roleNames.contains(roleInfo.getName())) throw new InvalidRelationTypeException( "Duplicate role name" + roleInfo.getName()); roleNames.add(roleInfo.getName()); } } } }