Source code: javax/management/relation/RelationSupport.java
1 /*
2 * JBoss, the OpenSource J2EE webOS
3 *
4 * Distributable under LGPL license.
5 * See terms of license at gnu.org.
6 */
7 package javax.management.relation;
8
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14
15 import javax.management.InstanceNotFoundException;
16 import javax.management.IntrospectionException;
17 import javax.management.MBeanException;
18 import javax.management.MBeanRegistration;
19 import javax.management.MBeanServer;
20 import javax.management.ObjectName;
21 import javax.management.ReflectionException;
22 import javax.management.RuntimeMBeanException;
23
24 import javax.management.relation.RelationServiceMBean;
25
26 import org.jboss.mx.util.MBeanProxy;
27 import org.jboss.mx.util.MBeanProxyCreationException;
28
29 /**
30 * Implements the management interface for a relation
31 * created internally within the relation service. The relation can
32 * have only roles - no attributes or methods.<p>
33 *
34 * The relation support managed bean can be created externally, including
35 * extending it, and then registered with the relation service.<p>
36 *
37 * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
38 * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>
39 *
40 * @version $Revision: 1.5.6.1 $
41 *
42 * <p><b>Revisions:</b>
43 *
44 * <p><b>20020412 Juha Lindfors:</b>
45 * <ul>
46 * <li>Changed MBeanProxy exception handling on create methods -- only need to
47 * catch one MBeanProxyCreationException
48 * </li>
49 * </ul>
50 */
51 public class RelationSupport
52 implements RelationSupportMBean, MBeanRegistration
53 {
54 // Constants -----------------------------------------------------
55
56 // Attributes ----------------------------------------------------
57
58 /**
59 * The relation id.
60 */
61 String relationId;
62
63 /**
64 * The relation service
65 */
66 ObjectName relationService;
67
68 /**
69 * A proxy to the relation service
70 */
71 private RelationServiceMBean serviceProxy;
72
73 /**
74 * The mbean server
75 */
76 MBeanServer server;
77
78 /**
79 * The relation type name
80 */
81 String relationTypeName;
82
83 /**
84 * The roles mapped by role name
85 */
86 HashMap roles;
87
88 /**
89 * Wether this relation is registered in the relation service
90 */
91 Boolean registered;
92
93 // Static --------------------------------------------------------
94
95 // Constructors --------------------------------------------------
96
97 /**
98 * Construct a new relation support object.<p>
99 *
100 * This constructor is intended for use when manually registrating
101 * a relation support object or an class that extends it.<p>
102 *
103 * Constructing the object does not register it with the relation
104 * service, only the following is validated at this stage.<p>
105 *
106 * The relation id is mandatory.<br>
107 * The relation service name is mandatory.<br>.
108 * The relation type name is mandatory.<br>
109 * The same name is used for more than one role.<p>
110 *
111 * @param relationId the relation Id
112 * @param relationService the object name of the relation service
113 * @param relationTypeName the name of the relation type
114 * @param roleList the roles in this relation
115 * @exception IllegalArgumentException for null values.
116 * @exception InvalidRoleValueException when two roles have the same name.
117 */
118 public RelationSupport(String relationId, ObjectName relationService,
119 String relationTypeName, RoleList roleList)
120 throws IllegalArgumentException, InvalidRoleValueException
121 {
122 init(relationId, relationService, null, relationTypeName, roleList);
123 }
124
125 /**
126 * Construct a new relation support object.<p>
127 *
128 * This constructor is intended for use when manually registrating
129 * a relation that delegates to relation support.<p>
130 *
131 * Constructing the object does not register it with the relation
132 * service, only the following is validated at this stage.<p>
133 *
134 * The relation id is mandatory.<br>
135 * The relation service name is mandatory.<br>.
136 * The mbean service is mandatory.<br>.
137 * The relation type name is mandatory.<br>
138 * The same name is used for more than one role.<p>
139 *
140 * @param relationId the relation Id
141 * @param relationService the object name of the relation service
142 * @param mbeanServer the object name of the relation service
143 * @param relationTypeName the name of the relation type
144 * @param roleList the roles in this relation
145 * @exception IllegalArgumentException for null values.
146 * @exception InvalidRoleValueException when two roles have the same name.
147 */
148 public RelationSupport(String relationId, ObjectName relationService,
149 MBeanServer mbeanServer, String relationTypeName,
150 RoleList roleList)
151 throws IllegalArgumentException, InvalidRoleValueException
152 {
153 init(relationId, relationService, mbeanServer, relationTypeName,
154 roleList);
155 }
156
157 // Relation implementation -----------------------------------------
158
159 public RoleResult getAllRoles()
160 throws RelationServiceNotRegisteredException
161 {
162 RoleList resolvedResult = new RoleList();
163 RoleUnresolvedList unresolvedResult = new RoleUnresolvedList();
164 RoleResult result = new RoleResult(resolvedResult, unresolvedResult);
165 synchronized (roles)
166 {
167 Iterator iterator = roles.values().iterator();
168 while (iterator.hasNext())
169 {
170 Role role = (Role) iterator.next();
171 int status = checkRoleReadable(role);
172 if (status == 0)
173 resolvedResult.add(role);
174 else
175 unresolvedResult.add(new RoleUnresolved(role.getRoleName(),
176 role.getRoleValue(),
177 status));
178 }
179 }
180 return result;
181 }
182
183 public Map getReferencedMBeans()
184 {
185 HashMap result = new HashMap();
186 synchronized (roles)
187 {
188 // Look through the roles in this relation
189 Iterator iterator = roles.values().iterator();
190 while (iterator.hasNext())
191 {
192 Role role = (Role) iterator.next();
193 String roleName = role.getRoleName();
194
195 // Get the mbeans in the role
196 ArrayList mbeans = (ArrayList) role.getRoleValue();
197
198 for (int i = 0; i < mbeans.size(); i++)
199 {
200 ObjectName mbean = (ObjectName) mbeans.get(i);
201
202 // Make sure this mbean has an entry
203 ArrayList resultRoles = (ArrayList) result.get(mbean);
204 if (resultRoles == null)
205 {
206 resultRoles = new ArrayList();
207 result.put(mbean, resultRoles);
208 }
209
210 // It seems the role name should be duplicated?
211 // Include the following test if this is a bug in RI.
212 // if (resultRoles.contains(roleName) == false)
213
214 // Add the role to this mbean
215 resultRoles.add(roleName);
216 }
217 }
218 }
219
220 // All done
221 return result;
222 }
223
224 public String getRelationId()
225 {
226 return relationId;
227 }
228
229 public ObjectName getRelationServiceName()
230 {
231 return relationService;
232 }
233
234 public String getRelationTypeName()
235 {
236 return relationTypeName;
237 }
238
239 public List getRole(String roleName)
240 throws IllegalArgumentException, RoleNotFoundException,
241 RelationServiceNotRegisteredException
242 {
243 if (roleName == null)
244 throw new IllegalArgumentException("null role name");
245 validateRoleReadable(roleName);
246 Role role = validateRoleFound(roleName);
247 return role.getRoleValue();
248 }
249
250 public Integer getRoleCardinality(String roleName)
251 throws IllegalArgumentException, RoleNotFoundException
252 {
253 if (roleName == null)
254 throw new IllegalArgumentException("null role name");
255 Role role = validateRoleFound(roleName);
256 return new Integer(role.getRoleValue().size());
257 }
258
259 public RoleResult getRoles(String[] roleNames)
260 throws IllegalArgumentException, RelationServiceNotRegisteredException
261 {
262 RoleList resolvedResult = new RoleList();
263 RoleUnresolvedList unresolvedResult = new RoleUnresolvedList();
264 RoleResult result = new RoleResult(resolvedResult, unresolvedResult);
265 for (int i = 0; i < roleNames.length; i++)
266 {
267 Role role = (Role) roles.get(roleNames[i]);
268 int status = checkRoleReadable(role);
269 if (status == 0)
270 resolvedResult.add(role);
271 else
272 unresolvedResult.add(new RoleUnresolved(role.getRoleName(),
273 role.getRoleValue(),
274 status));
275 }
276 return result;
277 }
278
279 public void handleMBeanUnregistration(ObjectName objectName, String roleName)
280 throws RoleNotFoundException, InvalidRoleValueException,
281 RelationServiceNotRegisteredException, RelationTypeNotFoundException,
282 RelationNotFoundException
283 {
284 checkRegistered();
285 Role role = validateRoleFound(roleName);
286 ArrayList values = (ArrayList) role.getRoleValue();
287 ArrayList oldRoleValue = new ArrayList(values);
288 if (values.remove(objectName) == false)
289 throw new InvalidRoleValueException(roleName + " " + objectName.toString());
290 updateRole(role, oldRoleValue);
291 }
292
293 public RoleList retrieveAllRoles()
294 {
295 RoleList result = new RoleList(roles.size());
296 synchronized (roles)
297 {
298 Iterator iterator = roles.values().iterator();
299 while (iterator.hasNext())
300 result.add((Role) iterator.next());
301 }
302 return result;
303 }
304
305 public void setRole(Role role)
306 throws IllegalArgumentException, InvalidRoleValueException,
307 RoleNotFoundException, RelationServiceNotRegisteredException,
308 RelationTypeNotFoundException, RelationNotFoundException
309 {
310 if (role == null)
311 throw new IllegalArgumentException("null role");
312 Role copy = (Role) role.clone();
313 checkRegistered();
314 RoleValidator.validateRole(relationService, server, relationTypeName, copy,
315 true);
316 Role oldRole = (Role) roles.get(role.getRoleName());
317 ArrayList oldRoleValue = (ArrayList) oldRole.getRoleValue();
318 updateRole(copy, oldRoleValue);
319 }
320
321 public RoleResult setRoles(RoleList roleList)
322 throws IllegalArgumentException, RelationServiceNotRegisteredException,
323 RelationTypeNotFoundException, RelationNotFoundException
324 {
325 if (roleList == null)
326 throw new IllegalArgumentException("null role list");
327 RoleList copy = new RoleList(roleList);
328 checkRegistered();
329 RoleResult result = RoleValidator.checkRoles(relationService, server,
330 relationTypeName, copy, true);
331 synchronized (result.getRoles())
332 {
333 Iterator iterator = result.getRoles().iterator();
334 while (iterator.hasNext())
335 {
336 Role role = (Role) iterator.next();
337 Role oldRole = (Role) roles.get(role.getRoleName());
338 ArrayList oldRoleValue = (ArrayList) oldRole.getRoleValue();
339 updateRole(role, oldRoleValue);
340 }
341 }
342 return result;
343 }
344
345 // RelationSupport implementation --------------------------------
346
347 public Boolean isInRelationService()
348 {
349 return registered;
350 }
351
352 public void setRelationServiceManagementFlag(Boolean value)
353 {
354 synchronized (registered)
355 {
356 registered = new Boolean(value.booleanValue());
357 }
358 }
359
360 // MBeanRegistration implementation ------------------------------
361
362 public ObjectName preRegister(MBeanServer server, ObjectName objectName)
363 throws Exception
364 {
365 this.server = server;
366 return objectName;
367 }
368
369 public void postRegister(Boolean registered)
370 {
371 }
372
373 public void preDeregister()
374 throws Exception
375 {
376 }
377
378 public void postDeregister()
379 {
380 server = null;
381 }
382
383 // Private ----------------------------------------------------------
384
385 /**
386 * Constructor support.<p>
387 *
388 * See the constructors for more information
389 *
390 * @param relationId the relation Id
391 * @param relationService the object name of the relation service
392 * @param mbeanServer the object name of the relation service
393 * @param relationTypeName the name of the relation type
394 * @param roleList the roles in this relation
395 * @exception IllegalArgumentException for null values.
396 * @exception InvalidRoleValueException when two roles have the same name.
397 */
398 private void init(String relationId, ObjectName relationService,
399 MBeanServer mbeanServer, String relationTypeName,
400 RoleList roleList)
401 throws IllegalArgumentException, InvalidRoleValueException
402 {
403 // Validation
404 if (relationId == null)
405 throw new IllegalArgumentException("null relation id");
406 if (relationService == null)
407 throw new IllegalArgumentException("null relation service");
408 if (relationTypeName == null)
409 throw new IllegalArgumentException("null relation type name");
410
411 // Easy parameters
412 this.relationId = relationId;
413 this.relationTypeName = relationTypeName;
414 this.relationService = relationService;
415 if (mbeanServer != null)
416 server = mbeanServer;
417 registered = new Boolean(false);
418
419 // Set up a hash map for the roles for quicker access
420 if (roleList == null)
421 roles = new HashMap();
422 else
423 {
424 Object[] roleArray = roleList.toArray();
425 roles = new HashMap(roleArray.length);
426 for (int i = 0; i < roleArray.length; i++)
427 {
428 Role role = (Role) roleArray[i];
429 if (roles.containsKey(role.getRoleName()))
430 throw new IllegalArgumentException("duplicate role name");
431 roles.put(role.getRoleName(), role);
432 }
433 }
434 }
435
436 /**
437 * Check that we are registered with the relation service
438 *
439 * @exception RelationNotFoundException when the relation
440 * is not registered with the relation service.
441 */
442 private void checkRegistered()
443 throws RelationNotFoundException
444 {
445 if (isInRelationService().booleanValue() == false)
446 throw new RelationNotFoundException("not registered with relation service");
447 // What is the purpose of this flag? Why not invoke hasRelation?
448 }
449
450 /**
451 * Check a role is readable
452 *
453 * @param role the role to check
454 * @return zero for success a value from RoleStatus otherwise.
455 * @exception RelationServiceNotRegisteredException when the relation
456 * is not registered with an MBeanServer.
457 */
458 private int checkRoleReadable(Role role)
459 throws RelationServiceNotRegisteredException
460 {
461 checkServiceProxy();
462 try
463 {
464 return serviceProxy.checkRoleReading(role.getRoleName(),
465 relationTypeName).intValue();
466 }
467 // RelationTypeNotFound has to be a runtime exception because
468 // the spec doesn't allow for this exception
469 catch (RelationTypeNotFoundException e)
470 {
471 throw new RuntimeException(e.toString());
472 }
473 }
474
475 /**
476 * Check a role is writable
477 *
478 * @param role the role to check
479 * @param initFlag don't check the writeablitiy when this flag is true
480 * @return zero for success a value from RoleStatus otherwise.
481 * @exception RelationServiceNotRegisteredException when the relation
482 * is not registered with an MBeanServer.
483 * @exception RelationTypeNotFoundException when the relation type
484 * is not registered with the relation service
485 */
486 private int checkRoleWritable(Role role, boolean initFlag)
487 throws RelationServiceNotRegisteredException, RelationTypeNotFoundException
488 {
489 checkServiceProxy();
490 try
491 {
492 return serviceProxy.checkRoleWriting(role, relationTypeName,
493 new Boolean(initFlag)).intValue();
494 }
495 // RelationTypeNotFound has to be a runtime exception because
496 // the spec doesn't allow for this exception
497 catch (RelationTypeNotFoundException e)
498 {
499 throw new RuntimeException(e.toString());
500 }
501 }
502
503 /**
504 * Update the role
505 *
506 * @param role the role to set
507 * @param oldRoleVale the old role value
508 */
509 private void updateRole(Role role, ArrayList oldRoleValue)
510 {
511 roles.put(role.getRoleName(), role);
512 try
513 {
514 checkServiceProxy();
515 serviceProxy.updateRoleMap(relationId, role, oldRoleValue);
516 serviceProxy.sendRoleUpdateNotification(relationId, role, oldRoleValue);
517 }
518 catch (Exception e)
519 {
520 throw new RuntimeException(e.toString());
521 }
522 }
523
524 /**
525 * Validate the role is found
526 *
527 * @param roleName the role name to validate
528 * @return the found role
529 * @exception RoleNotFoundException when the role does not exist
530 */
531 private Role validateRoleFound(String roleName)
532 throws RoleNotFoundException
533 {
534 Role result = (Role) roles.get(roleName);
535 if (result == null)
536 throw new RoleNotFoundException(roleName);
537 return result;
538 }
539
540 /**
541 * Validate the role is readable, i.e. it is found and readable
542 *
543 * @param roleName the role name to validate
544 * @exception RoleNotFoundException when the role is not readable
545 * @exception RelationServiceNotRegisteredException when the relation
546 * is not registered with an MBeanServer.
547 */
548 private void validateRoleReadable(String roleName)
549 throws RoleNotFoundException, RelationServiceNotRegisteredException
550 {
551 int status = 0;
552 checkServiceProxy();
553 try
554 {
555 status = serviceProxy.checkRoleReading(roleName,
556 relationTypeName).intValue();
557 }
558 // RelationTypeNotFound has to be a runtime exception because
559 // the spec doesn't allow for this exception
560 catch (RelationTypeNotFoundException e)
561 {
562 throw new RuntimeException(e.toString());
563 }
564
565 if (status == 3)
566 throw new RoleNotFoundException(roleName);
567 if (status == 6)
568 throw new RoleNotFoundException(roleName + " is not readable");
569 }
570
571 /**
572 * Validate the role is writable, i.e. it is found and readable
573 *
574 * @param roleName the role name to validate
575 * @param initFlag don't check the writeability when this flag is true
576 * @return the found role
577 * @exception RoleNotFoundException when the role is not writable
578 * @exception RelationServiceNotRegisteredException when the relation
579 * is not registered with an MBeanServer.
580 * @exception RelationTypeNotFoundException when the relation type
581 * is not registered with the relation service
582 */
583 private Role validateRoleWritable(String roleName, boolean initFlag)
584 throws RoleNotFoundException, RelationServiceNotRegisteredException,
585 RelationTypeNotFoundException
586 {
587 Role result = validateRoleFound(roleName);
588 if (checkRoleWritable(result, initFlag) != 0)
589 throw new RoleNotFoundException("role not writable");
590 return result;
591 }
592
593 /**
594 * Check the relation service proxy has been constructed.
595 *
596 * @exception RelationServiceNotRegisteredException when the relation
597 * service has not been registered with the MBeanServer
598 */
599 private void checkServiceProxy()
600 throws RelationServiceNotRegisteredException
601 {
602 if (serviceProxy == null)
603 {
604 try
605 {
606 serviceProxy = (RelationServiceMBean) MBeanProxy.get(
607 RelationServiceMBean.class, relationService, server);
608 }
609 catch (MBeanProxyCreationException e)
610 {
611 throw new RelationServiceNotRegisteredException(e.toString());
612 }
613 }
614 }
615 }