001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.management.relation;
023:
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029:
030: import javax.management.MBeanRegistration;
031: import javax.management.MBeanServer;
032: import javax.management.ObjectName;
033:
034: import org.jboss.mx.util.MBeanProxyExt;
035:
036: /**
037: * Implements the management interface for a relation
038: * created internally within the relation service. The relation can
039: * have only roles - no attributes or methods.<p>
040: *
041: * The relation support managed bean can be created externally, including
042: * extending it, and then registered with the relation service.<p>
043: *
044: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
045: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>
046: *
047: * @version $Revision: 57200 $
048: *
049: * <p><b>Revisions:</b>
050: *
051: * <p><b>20020412 Juha Lindfors:</b>
052: * <ul>
053: * <li>Changed MBeanProxy exception handling on create methods -- only need to
054: * catch one MBeanProxyCreationException
055: * </li>
056: * </ul>
057: */
058: public class RelationSupport implements RelationSupportMBean,
059: MBeanRegistration {
060: // Constants -----------------------------------------------------
061:
062: // Attributes ----------------------------------------------------
063:
064: /**
065: * The relation id.
066: */
067: String relationId;
068:
069: /**
070: * The relation service
071: */
072: ObjectName relationService;
073:
074: /**
075: * A proxy to the relation service
076: */
077: private RelationServiceMBean serviceProxy;
078:
079: /**
080: * The mbean server
081: */
082: MBeanServer server;
083:
084: /**
085: * The relation type name
086: */
087: String relationTypeName;
088:
089: /**
090: * The roles mapped by role name
091: */
092: HashMap roles;
093:
094: /**
095: * Wether this relation is registered in the relation service
096: */
097: Boolean registered;
098:
099: // Static --------------------------------------------------------
100:
101: // Constructors --------------------------------------------------
102:
103: /**
104: * Construct a new relation support object.<p>
105: *
106: * This constructor is intended for use when manually registrating
107: * a relation support object or an class that extends it.<p>
108: *
109: * Constructing the object does not register it with the relation
110: * service, only the following is validated at this stage.<p>
111: *
112: * The relation id is mandatory.<br>
113: * The relation service name is mandatory.<br>.
114: * The relation type name is mandatory.<br>
115: * The same name is used for more than one role.<p>
116: *
117: * @param relationId the relation Id
118: * @param relationService the object name of the relation service
119: * @param relationTypeName the name of the relation type
120: * @param roleList the roles in this relation
121: * @exception IllegalArgumentException for null values.
122: * @exception InvalidRoleValueException when two roles have the same name.
123: */
124: public RelationSupport(String relationId,
125: ObjectName relationService, String relationTypeName,
126: RoleList roleList) throws IllegalArgumentException,
127: InvalidRoleValueException {
128: init(relationId, relationService, null, relationTypeName,
129: roleList);
130: }
131:
132: /**
133: * Construct a new relation support object.<p>
134: *
135: * This constructor is intended for use when manually registrating
136: * a relation that delegates to relation support.<p>
137: *
138: * Constructing the object does not register it with the relation
139: * service, only the following is validated at this stage.<p>
140: *
141: * The relation id is mandatory.<br>
142: * The relation service name is mandatory.<br>.
143: * The mbean service is mandatory.<br>.
144: * The relation type name is mandatory.<br>
145: * The same name is used for more than one role.<p>
146: *
147: * @param relationId the relation Id
148: * @param relationService the object name of the relation service
149: * @param mbeanServer the object name of the relation service
150: * @param relationTypeName the name of the relation type
151: * @param roleList the roles in this relation
152: * @exception IllegalArgumentException for null values.
153: * @exception InvalidRoleValueException when two roles have the same name.
154: */
155: public RelationSupport(String relationId,
156: ObjectName relationService, MBeanServer mbeanServer,
157: String relationTypeName, RoleList roleList)
158: throws IllegalArgumentException, InvalidRoleValueException {
159: init(relationId, relationService, mbeanServer,
160: relationTypeName, roleList);
161: }
162:
163: // Relation implementation -----------------------------------------
164:
165: public RoleResult getAllRoles()
166: throws RelationServiceNotRegisteredException {
167: RoleList resolvedResult = new RoleList();
168: RoleUnresolvedList unresolvedResult = new RoleUnresolvedList();
169: RoleResult result = new RoleResult(resolvedResult,
170: unresolvedResult);
171: synchronized (roles) {
172: Iterator iterator = roles.values().iterator();
173: while (iterator.hasNext()) {
174: Role role = (Role) iterator.next();
175: int status = checkRoleReadable(role);
176: if (status == 0)
177: resolvedResult.add(role);
178: else
179: unresolvedResult
180: .add(new RoleUnresolved(role.getRoleName(),
181: role.getRoleValue(), status));
182: }
183: }
184: return result;
185: }
186:
187: public Map getReferencedMBeans() {
188: HashMap result = new HashMap();
189: synchronized (roles) {
190: // Look through the roles in this relation
191: Iterator iterator = roles.values().iterator();
192: while (iterator.hasNext()) {
193: Role role = (Role) iterator.next();
194: String roleName = role.getRoleName();
195:
196: // Get the mbeans in the role
197: ArrayList mbeans = (ArrayList) role.getRoleValue();
198: Iterator mbeanIterator = mbeans.iterator();
199: while (mbeanIterator.hasNext()) {
200: ObjectName mbean = (ObjectName) mbeanIterator
201: .next();
202:
203: // Make sure this mbean has an entry
204: ArrayList resultRoles = (ArrayList) result
205: .get(mbean);
206: if (resultRoles == null) {
207: resultRoles = new ArrayList();
208: result.put(mbean, resultRoles);
209: }
210:
211: // It seems the role name should be duplicated?
212: // Include the following test if this is a bug in RI.
213: // if (resultRoles.contains(roleName) == false)
214:
215: // Add the role to this mbean
216: resultRoles.add(roleName);
217: }
218: }
219: }
220:
221: // All done
222: return result;
223: }
224:
225: public String getRelationId() {
226: return relationId;
227: }
228:
229: public ObjectName getRelationServiceName() {
230: return relationService;
231: }
232:
233: public String getRelationTypeName() {
234: return relationTypeName;
235: }
236:
237: public List getRole(String roleName)
238: throws IllegalArgumentException, RoleNotFoundException,
239: RelationServiceNotRegisteredException {
240: if (roleName == null)
241: throw new IllegalArgumentException("null role name");
242: validateRoleReadable(roleName);
243: Role role = validateRoleFound(roleName);
244: return role.getRoleValue();
245: }
246:
247: public Integer getRoleCardinality(String roleName)
248: throws IllegalArgumentException, RoleNotFoundException {
249: if (roleName == null)
250: throw new IllegalArgumentException("null role name");
251: Role role = validateRoleFound(roleName);
252: return new Integer(role.getRoleValue().size());
253: }
254:
255: public RoleResult getRoles(String[] roleNames)
256: throws IllegalArgumentException,
257: RelationServiceNotRegisteredException {
258: RoleList resolvedResult = new RoleList();
259: RoleUnresolvedList unresolvedResult = new RoleUnresolvedList();
260: RoleResult result = new RoleResult(resolvedResult,
261: unresolvedResult);
262: for (int i = 0; i < roleNames.length; i++) {
263: int status = RoleStatus.NO_ROLE_WITH_NAME;
264: List roleValue;
265: Role role = (Role) roles.get(roleNames[i]);
266: if (role != null) {
267: roleValue = role.getRoleValue();
268: status = checkRoleReadable(role);
269: } else
270: roleValue = new ArrayList();
271:
272: if (status == 0)
273: resolvedResult.add(role);
274: else
275: unresolvedResult.add(new RoleUnresolved(roleNames[i],
276: roleValue, status));
277: }
278: return result;
279: }
280:
281: public void handleMBeanUnregistration(ObjectName objectName,
282: String roleName) throws IllegalArgumentException,
283: RoleNotFoundException, InvalidRoleValueException,
284: RelationServiceNotRegisteredException,
285: RelationTypeNotFoundException, RelationNotFoundException {
286: checkRegistered();
287: Role role = validateRoleFound(roleName);
288: ArrayList values = (ArrayList) role.getRoleValue();
289: ArrayList oldRoleValue = new ArrayList(values);
290: if (values.remove(objectName) == false)
291: throw new InvalidRoleValueException(roleName + " "
292: + objectName.toString());
293: role.setRoleValue(values);
294: updateRole(role, oldRoleValue);
295: }
296:
297: public RoleList retrieveAllRoles() {
298: RoleList result = new RoleList(roles.size());
299: synchronized (roles) {
300: Iterator iterator = roles.values().iterator();
301: while (iterator.hasNext())
302: result.add((Role) iterator.next());
303: }
304: return result;
305: }
306:
307: public void setRole(Role role) throws IllegalArgumentException,
308: RoleNotFoundException, RelationTypeNotFoundException,
309: InvalidRoleValueException,
310: RelationServiceNotRegisteredException,
311: RelationNotFoundException {
312: if (role == null)
313: throw new IllegalArgumentException("null role");
314: Role copy = (Role) role.clone();
315: checkRegistered();
316: RoleValidator.validateRole(relationService, server,
317: relationTypeName, copy, true);
318: Role oldRole = (Role) roles.get(role.getRoleName());
319: ArrayList oldRoleValue = (ArrayList) oldRole.getRoleValue();
320: updateRole(copy, oldRoleValue);
321: }
322:
323: public RoleResult setRoles(RoleList roleList)
324: throws IllegalArgumentException,
325: RelationServiceNotRegisteredException,
326: RelationTypeNotFoundException, RelationNotFoundException {
327: if (roleList == null)
328: throw new IllegalArgumentException("null role list");
329: RoleList copy = new RoleList(roleList);
330: checkRegistered();
331: RoleResult result = RoleValidator.checkRoles(relationService,
332: server, relationTypeName, copy, true);
333: synchronized (result.getRoles()) {
334: Iterator iterator = result.getRoles().iterator();
335: while (iterator.hasNext()) {
336: Role role = (Role) iterator.next();
337: Role oldRole = (Role) roles.get(role.getRoleName());
338: ArrayList oldRoleValue = (ArrayList) oldRole
339: .getRoleValue();
340: updateRole(role, oldRoleValue);
341: }
342: }
343: return result;
344: }
345:
346: // RelationSupport implementation --------------------------------
347:
348: public Boolean isInRelationService() {
349: return registered;
350: }
351:
352: public void setRelationServiceManagementFlag(Boolean value)
353: throws IllegalArgumentException {
354: synchronized (registered) {
355: registered = new Boolean(value.booleanValue());
356: }
357: }
358:
359: // MBeanRegistration implementation ------------------------------
360:
361: public ObjectName preRegister(MBeanServer server,
362: ObjectName objectName) throws Exception {
363: this .server = server;
364: return objectName;
365: }
366:
367: public void postRegister(Boolean registered) {
368: }
369:
370: public void preDeregister() throws Exception {
371: }
372:
373: public void postDeregister() {
374: server = null;
375: }
376:
377: // Private ----------------------------------------------------------
378:
379: /**
380: * Constructor support.<p>
381: *
382: * See the constructors for more information
383: *
384: * @param relationId the relation Id
385: * @param relationService the object name of the relation service
386: * @param mbeanServer the object name of the relation service
387: * @param relationTypeName the name of the relation type
388: * @param roleList the roles in this relation
389: * @exception IllegalArgumentException for null values.
390: */
391: private void init(String relationId, ObjectName relationService,
392: MBeanServer mbeanServer, String relationTypeName,
393: RoleList roleList) throws IllegalArgumentException {
394: // Validation
395: if (relationId == null)
396: throw new IllegalArgumentException("null relation id");
397: if (relationService == null)
398: throw new IllegalArgumentException("null relation service");
399: if (relationTypeName == null)
400: throw new IllegalArgumentException(
401: "null relation type name");
402:
403: // Easy parameters
404: this .relationId = relationId;
405: this .relationTypeName = relationTypeName;
406: this .relationService = relationService;
407: if (mbeanServer != null)
408: server = mbeanServer;
409: registered = new Boolean(false);
410:
411: // Set up a hash map for the roles for quicker access
412: if (roleList == null)
413: roles = new HashMap();
414: else {
415: Object[] roleArray = roleList.toArray();
416: roles = new HashMap(roleArray.length);
417: for (int i = 0; i < roleArray.length; i++) {
418: Role role = (Role) roleArray[i];
419: if (roles.containsKey(role.getRoleName()))
420: throw new IllegalArgumentException(
421: "duplicate role name");
422: Role copy = (Role) role.clone();
423: roles.put(role.getRoleName(), copy);
424: }
425: }
426: }
427:
428: /**
429: * Check that we are registered with the relation service
430: *
431: * @exception RelationNotFoundException when the relation
432: * is not registered with the relation service.
433: */
434: private void checkRegistered() throws RelationNotFoundException {
435: if (isInRelationService().booleanValue() == false)
436: throw new RelationNotFoundException(
437: "not registered with relation service");
438: // What is the purpose of this flag? Why not invoke hasRelation?
439: }
440:
441: /**
442: * Check a role is readable
443: *
444: * @param role the role to check
445: * @return zero for success a value from RoleStatus otherwise.
446: * @exception RelationServiceNotRegisteredException when the relation
447: * is not registered with an MBeanServer.
448: */
449: private int checkRoleReadable(Role role)
450: throws RelationServiceNotRegisteredException {
451: checkServiceProxy();
452: try {
453: String roleName = role.getRoleName();
454: Integer result = serviceProxy.checkRoleReading(roleName,
455: relationTypeName);
456: return result.intValue();
457: }
458: // RelationTypeNotFound has to be a runtime exception because
459: // the spec doesn't allow for this exception
460: catch (RelationTypeNotFoundException e) {
461: throw new RuntimeException(e.toString());
462: }
463: }
464:
465: /**
466: * Update the role
467: *
468: * @param role the role to set
469: * @param oldRoleValue the old role value
470: */
471: private void updateRole(Role role, ArrayList oldRoleValue) {
472: roles.put(role.getRoleName(), role);
473: try {
474: checkServiceProxy();
475: serviceProxy.updateRoleMap(relationId, role, oldRoleValue);
476: serviceProxy.sendRoleUpdateNotification(relationId, role,
477: oldRoleValue);
478: } catch (Exception e) {
479: throw new RuntimeException(e.toString());
480: }
481: }
482:
483: /**
484: * Validate the role is found
485: *
486: * @param roleName the role name to validate
487: * @return the found role
488: * @exception RoleNotFoundException when the role does not exist
489: */
490: private Role validateRoleFound(String roleName)
491: throws RoleNotFoundException {
492: Role result = (Role) roles.get(roleName);
493: if (result == null)
494: throw new RoleNotFoundException(roleName);
495: return result;
496: }
497:
498: /**
499: * Validate the role is readable, i.e. it is found and readable
500: *
501: * @param roleName the role name to validate
502: * @exception RoleNotFoundException when the role is not readable
503: * @exception RelationServiceNotRegisteredException when the relation
504: * is not registered with an MBeanServer.
505: */
506: private void validateRoleReadable(String roleName)
507: throws RoleNotFoundException,
508: RelationServiceNotRegisteredException {
509: int status = 0;
510: checkServiceProxy();
511: try {
512: status = serviceProxy.checkRoleReading(roleName,
513: relationTypeName).intValue();
514: }
515: // RelationTypeNotFound has to be a runtime exception because
516: // the spec doesn't allow for this exception
517: catch (RelationTypeNotFoundException e) {
518: throw new RuntimeException(e.toString());
519: }
520:
521: if (status == RoleStatus.NO_ROLE_WITH_NAME)
522: throw new RoleNotFoundException(roleName);
523: if (status == RoleStatus.ROLE_NOT_READABLE)
524: throw new RoleNotFoundException(roleName
525: + " is not readable");
526: }
527:
528: /**
529: * Check the relation service proxy has been constructed.
530: *
531: * @exception RelationServiceNotRegisteredException when the relation
532: * service has not been registered with the MBeanServer
533: */
534: private void checkServiceProxy()
535: throws RelationServiceNotRegisteredException {
536: if (serviceProxy == null) {
537: try {
538: serviceProxy = (RelationServiceMBean) MBeanProxyExt
539: .create(RelationServiceMBean.class,
540: relationService, server);
541: } catch (Exception e) {
542: throw new RelationServiceNotRegisteredException(e
543: .toString());
544: }
545: }
546: }
547: }
|