History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/management/relation/RelationService.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/management/relation/RelationService.java+3790−0
@@ -0,0 +1,3790 @@
1+/*
2+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.management.relation;
27+
28+import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER;
29+import static com.sun.jmx.mbeanserver.Util.cast;
30+
31+import java.util.ArrayList;
32+import java.util.Date;
33+import java.util.HashMap;
34+import java.util.Iterator;
35+import java.util.List;
36+import java.util.Map;
37+import java.util.Set;
38+import java.util.concurrent.atomic.AtomicLong;
39+import java.util.logging.Level;
40+
41+import javax.management.Attribute;
42+import javax.management.AttributeNotFoundException;
43+import javax.management.InstanceNotFoundException;
44+import javax.management.InvalidAttributeValueException;
45+import javax.management.MBeanException;
46+import javax.management.MBeanNotificationInfo;
47+import javax.management.MBeanRegistration;
48+import javax.management.MBeanServer;
49+import javax.management.MBeanServerDelegate;
50+import javax.management.MBeanServerNotification;
51+import javax.management.Notification;
52+import javax.management.NotificationBroadcasterSupport;
53+import javax.management.NotificationListener;
54+import javax.management.ObjectName;
55+import javax.management.ReflectionException;
56+
57+/**
58+ * The Relation Service is in charge of creating and deleting relation types
59+ * and relations, of handling the consistency and of providing query
60+ * mechanisms.
61+ * <P>It implements the NotificationBroadcaster by extending
62+ * NotificationBroadcasterSupport to send notifications when a relation is
63+ * removed from it.
64+ * <P>It implements the NotificationListener interface to be able to receive
65+ * notifications concerning unregistration of MBeans referenced in relation
66+ * roles and of relation MBeans.
67+ * <P>It implements the MBeanRegistration interface to be able to retrieve
68+ * its ObjectName and MBean Server.
69+ *
70+ * @since 1.5
71+ */
72+public class RelationService extends NotificationBroadcasterSupport
73+ implements RelationServiceMBean, MBeanRegistration, NotificationListener {
74+
75+ //
76+ // Private members
77+ //
78+
79+ // Map associating:
80+ // <relation id> -> <RelationSupport object/ObjectName>
81+ // depending if the relation has been created using createRelation()
82+ // method (so internally handled) or is an MBean added as a relation by the
83+ // user
84+ private Map<String,Object> myRelId2ObjMap = new HashMap<String,Object>();
85+
86+ // Map associating:
87+ // <relation id> -> <relation type name>
88+ private Map<String,String> myRelId2RelTypeMap = new HashMap<String,String>();
89+
90+ // Map associating:
91+ // <relation MBean Object Name> -> <relation id>
92+ private Map<ObjectName,String> myRelMBeanObjName2RelIdMap =
93+ new HashMap<ObjectName,String>();
94+
95+ // Map associating:
96+ // <relation type name> -> <RelationType object>
97+ private Map<String,RelationType> myRelType2ObjMap =
98+ new HashMap<String,RelationType>();
99+
100+ // Map associating:
101+ // <relation type name> -> ArrayList of <relation id>
102+ // to list all the relations of a given type
103+ private Map<String,List<String>> myRelType2RelIdsMap =
104+ new HashMap<String,List<String>>();
105+
106+ // Map associating:
107+ // <ObjectName> -> HashMap
108+ // the value HashMap mapping:
109+ // <relation id> -> ArrayList of <role name>
110+ // to track where a given MBean is referenced.
111+ private final Map<ObjectName,Map<String,List<String>>>
112+ myRefedMBeanObjName2RelIdsMap =
113+ new HashMap<ObjectName,Map<String,List<String>>>();
114+
115+ // Flag to indicate if, when a notification is received for the
116+ // unregistration of an MBean referenced in a relation, if an immediate
117+ // "purge" of the relations (look for the relations no
118+ // longer valid) has to be performed , or if that will be performed only
119+ // when the purgeRelations method will be explicitly called.
120+ // true is immediate purge.
121+ private boolean myPurgeFlag = true;
122+
123+ // Internal counter to provide sequence numbers for notifications sent by:
124+ // - the Relation Service
125+ // - a relation handled by the Relation Service
126+ private final AtomicLong atomicSeqNo = new AtomicLong();
127+
128+ // ObjectName used to register the Relation Service in the MBean Server
129+ private ObjectName myObjName = null;
130+
131+ // MBean Server where the Relation Service is registered
132+ private MBeanServer myMBeanServer = null;
133+
134+ // Filter registered in the MBean Server with the Relation Service to be
135+ // informed of referenced MBean unregistrations
136+ private MBeanServerNotificationFilter myUnregNtfFilter = null;
137+
138+ // List of unregistration notifications received (storage used if purge
139+ // of relations when unregistering a referenced MBean is not immediate but
140+ // on user request)
141+ private List<MBeanServerNotification> myUnregNtfList =
142+ new ArrayList<MBeanServerNotification>();
143+
144+ //
145+ // Constructor
146+ //
147+
148+ /**
149+ * Constructor.
150+ *
151+ * @param immediatePurgeFlag flag to indicate when a notification is
152+ * received for the unregistration of an MBean referenced in a relation, if
153+ * an immediate "purge" of the relations (look for the relations no
154+ * longer valid) has to be performed , or if that will be performed only
155+ * when the purgeRelations method will be explicitly called.
156+ * <P>true is immediate purge.
157+ */
158+ public RelationService(boolean immediatePurgeFlag) {
159+
160+ RELATION_LOGGER.entering(RelationService.class.getName(),
161+ "RelationService");
162+
163+ setPurgeFlag(immediatePurgeFlag);
164+
165+ RELATION_LOGGER.exiting(RelationService.class.getName(),
166+ "RelationService");
167+ return;
168+ }
169+
170+ /**
171+ * Checks if the Relation Service is active.
172+ * Current condition is that the Relation Service must be registered in the
173+ * MBean Server
174+ *
175+ * @exception RelationServiceNotRegisteredException if it is not
176+ * registered
177+ */
178+ public void isActive()
179+ throws RelationServiceNotRegisteredException {
180+ if (myMBeanServer == null) {
181+ // MBean Server not set by preRegister(): relation service not
182+ // registered
183+ String excMsg =
184+ "Relation Service not registered in the MBean Server.";
185+ throw new RelationServiceNotRegisteredException(excMsg);
186+ }
187+ return;
188+ }
189+
190+ //
191+ // MBeanRegistration interface
192+ //
193+
194+ // Pre-registration: retrieves its ObjectName and MBean Server
195+ //
196+ // No exception thrown.
197+ public ObjectName preRegister(MBeanServer server,
198+ ObjectName name)
199+ throws Exception {
200+
201+ myMBeanServer = server;
202+ myObjName = name;
203+ return name;
204+ }
205+
206+ // Post-registration: does nothing
207+ public void postRegister(Boolean registrationDone) {
208+ return;
209+ }
210+
211+ // Pre-unregistration: does nothing
212+ public void preDeregister()
213+ throws Exception {
214+ return;
215+ }
216+
217+ // Post-unregistration: does nothing
218+ public void postDeregister() {
219+ return;
220+ }
221+
222+ //
223+ // Accessors
224+ //
225+
226+ /**
227+ * Returns the flag to indicate if when a notification is received for the
228+ * unregistration of an MBean referenced in a relation, if an immediate
229+ * "purge" of the relations (look for the relations no longer valid)
230+ * has to be performed , or if that will be performed only when the
231+ * purgeRelations method will be explicitly called.
232+ * <P>true is immediate purge.
233+ *
234+ * @return true if purges are automatic.
235+ *
236+ * @see #setPurgeFlag
237+ */
238+ public boolean getPurgeFlag() {
239+ return myPurgeFlag;
240+ }
241+
242+ /**
243+ * Sets the flag to indicate if when a notification is received for the
244+ * unregistration of an MBean referenced in a relation, if an immediate
245+ * "purge" of the relations (look for the relations no longer valid)
246+ * has to be performed , or if that will be performed only when the
247+ * purgeRelations method will be explicitly called.
248+ * <P>true is immediate purge.
249+ *
250+ * @param purgeFlag flag
251+ *
252+ * @see #getPurgeFlag
253+ */
254+ public void setPurgeFlag(boolean purgeFlag) {
255+
256+ myPurgeFlag = purgeFlag;
257+ return;
258+ }
259+
260+ //
261+ // Relation type handling
262+ //
263+
264+ /**
265+ * Creates a relation type (a RelationTypeSupport object) with given
266+ * role infos (provided by the RoleInfo objects), and adds it in the
267+ * Relation Service.
268+ *
269+ * @param relationTypeName name of the relation type
270+ * @param roleInfoArray array of role infos
271+ *
272+ * @exception IllegalArgumentException if null parameter
273+ * @exception InvalidRelationTypeException If:
274+ * <P>- there is already a relation type with that name
275+ * <P>- the same name has been used for two different role infos
276+ * <P>- no role info provided
277+ * <P>- one null role info provided
278+ */
279+ public void createRelationType(String relationTypeName,
280+ RoleInfo[] roleInfoArray)
281+ throws IllegalArgumentException,
282+ InvalidRelationTypeException {
283+
284+ if (relationTypeName == null || roleInfoArray == null) {
285+ String excMsg = "Invalid parameter.";
286+ throw new IllegalArgumentException(excMsg);
287+ }
288+
289+ RELATION_LOGGER.entering(RelationService.class.getName(),
290+ "createRelationType", relationTypeName);
291+
292+ // Can throw an InvalidRelationTypeException
293+ RelationType relType =
294+ new RelationTypeSupport(relationTypeName, roleInfoArray);
295+
296+ addRelationTypeInt(relType);
297+
298+ RELATION_LOGGER.exiting(RelationService.class.getName(),
299+ "createRelationType");
300+ return;
301+ }
302+
303+ /**
304+ * Adds given object as a relation type. The object is expected to
305+ * implement the RelationType interface.
306+ *
307+ * @param relationTypeObj relation type object (implementing the
308+ * RelationType interface)
309+ *
310+ * @exception IllegalArgumentException if null parameter or if
311+ * {@link RelationType#getRelationTypeName
312+ * relationTypeObj.getRelationTypeName()} returns null.
313+ * @exception InvalidRelationTypeException if:
314+ * <P>- the same name has been used for two different roles
315+ * <P>- no role info provided
316+ * <P>- one null role info provided
317+ * <P>- there is already a relation type with that name
318+ */
319+ public void addRelationType(RelationType relationTypeObj)
320+ throws IllegalArgumentException,
321+ InvalidRelationTypeException {
322+
323+ if (relationTypeObj == null) {
324+ String excMsg = "Invalid parameter.";
325+ throw new IllegalArgumentException(excMsg);
326+ }
327+
328+ RELATION_LOGGER.entering(RelationService.class.getName(),
329+ "addRelationType");
330+
331+ // Checks the role infos
332+ List<RoleInfo> roleInfoList = relationTypeObj.getRoleInfos();
333+ if (roleInfoList == null) {
334+ String excMsg = "No role info provided.";
335+ throw new InvalidRelationTypeException(excMsg);
336+ }
337+
338+ RoleInfo[] roleInfoArray = new RoleInfo[roleInfoList.size()];
339+ int i = 0;
340+ for (RoleInfo currRoleInfo : roleInfoList) {
341+ roleInfoArray[i] = currRoleInfo;
342+ i++;
343+ }
344+ // Can throw InvalidRelationTypeException
345+ RelationTypeSupport.checkRoleInfos(roleInfoArray);
346+
347+ addRelationTypeInt(relationTypeObj);
348+
349+ RELATION_LOGGER.exiting(RelationService.class.getName(),
350+ "addRelationType");
351+ return;
352+ }
353+
354+ /**
355+ * Retrieves names of all known relation types.
356+ *
357+ * @return ArrayList of relation type names (Strings)
358+ */
359+ public List<String> getAllRelationTypeNames() {
360+ ArrayList<String> result;
361+ synchronized(myRelType2ObjMap) {
362+ result = new ArrayList<String>(myRelType2ObjMap.keySet());
363+ }
364+ return result;
365+ }
366+
367+ /**
368+ * Retrieves list of role infos (RoleInfo objects) of a given relation
369+ * type.
370+ *
371+ * @param relationTypeName name of relation type
372+ *
373+ * @return ArrayList of RoleInfo.
374+ *
375+ * @exception IllegalArgumentException if null parameter
376+ * @exception RelationTypeNotFoundException if there is no relation type
377+ * with that name.
378+ */
379+ public List<RoleInfo> getRoleInfos(String relationTypeName)
380+ throws IllegalArgumentException,
381+ RelationTypeNotFoundException {
382+
383+ if (relationTypeName == null) {
384+ String excMsg = "Invalid parameter.";
385+ throw new IllegalArgumentException(excMsg);
386+ }
387+
388+ RELATION_LOGGER.entering(RelationService.class.getName(),
389+ "getRoleInfos", relationTypeName);
390+
391+ // Can throw a RelationTypeNotFoundException
392+ RelationType relType = getRelationType(relationTypeName);
393+
394+ RELATION_LOGGER.exiting(RelationService.class.getName(),
395+ "getRoleInfos");
396+ return relType.getRoleInfos();
397+ }
398+
399+ /**
400+ * Retrieves role info for given role name of a given relation type.
401+ *
402+ * @param relationTypeName name of relation type
403+ * @param roleInfoName name of role
404+ *
405+ * @return RoleInfo object.
406+ *
407+ * @exception IllegalArgumentException if null parameter
408+ * @exception RelationTypeNotFoundException if the relation type is not
409+ * known in the Relation Service
410+ * @exception RoleInfoNotFoundException if the role is not part of the
411+ * relation type.
412+ */
413+ public RoleInfo getRoleInfo(String relationTypeName,
414+ String roleInfoName)
415+ throws IllegalArgumentException,
416+ RelationTypeNotFoundException,
417+ RoleInfoNotFoundException {
418+
419+ if (relationTypeName == null || roleInfoName == null) {
420+ String excMsg = "Invalid parameter.";
421+ throw new IllegalArgumentException(excMsg);
422+ }
423+
424+ RELATION_LOGGER.entering(RelationService.class.getName(),
425+ "getRoleInfo", new Object[] {relationTypeName, roleInfoName});
426+
427+ // Can throw a RelationTypeNotFoundException
428+ RelationType relType = getRelationType(relationTypeName);
429+
430+ // Can throw a RoleInfoNotFoundException
431+ RoleInfo roleInfo = relType.getRoleInfo(roleInfoName);
432+
433+ RELATION_LOGGER.exiting(RelationService.class.getName(),
434+ "getRoleInfo");
435+ return roleInfo;
436+ }
437+
438+ /**
439+ * Removes given relation type from Relation Service.
440+ * <P>The relation objects of that type will be removed from the
441+ * Relation Service.
442+ *
443+ * @param relationTypeName name of the relation type to be removed
444+ *
445+ * @exception RelationServiceNotRegisteredException if the Relation
446+ * Service is not registered in the MBean Server
447+ * @exception IllegalArgumentException if null parameter
448+ * @exception RelationTypeNotFoundException If there is no relation type
449+ * with that name
450+ */
451+ public void removeRelationType(String relationTypeName)
452+ throws RelationServiceNotRegisteredException,
453+ IllegalArgumentException,
454+ RelationTypeNotFoundException {
455+
456+ // Can throw RelationServiceNotRegisteredException
457+ isActive();
458+
459+ if (relationTypeName == null) {
460+ String excMsg = "Invalid parameter.";
461+ throw new IllegalArgumentException(excMsg);
462+ }
463+
464+ RELATION_LOGGER.entering(RelationService.class.getName(),
465+ "removeRelationType", relationTypeName);
466+
467+ // Checks if the relation type to be removed exists
468+ // Can throw a RelationTypeNotFoundException
469+ RelationType relType = getRelationType(relationTypeName);
470+
471+ // Retrieves the relation ids for relations of that type
472+ List<String> relIdList = null;
473+ synchronized(myRelType2RelIdsMap) {
474+ // Note: take a copy of the list as it is a part of a map that
475+ // will be updated by removeRelation() below.
476+ List<String> relIdList1 =
477+ myRelType2RelIdsMap.get(relationTypeName);
478+ if (relIdList1 != null) {
479+ relIdList = new ArrayList<String>(relIdList1);
480+ }
481+ }
482+
483+ // Removes the relation type from all maps
484+ synchronized(myRelType2ObjMap) {
485+ myRelType2ObjMap.remove(relationTypeName);
486+ }
487+ synchronized(myRelType2RelIdsMap) {
488+ myRelType2RelIdsMap.remove(relationTypeName);
489+ }
490+
491+ // Removes all relations of that type
492+ if (relIdList != null) {
493+ for (String currRelId : relIdList) {
494+ // Note: will remove it from myRelId2RelTypeMap :)
495+ //
496+ // Can throw RelationServiceNotRegisteredException (detected
497+ // above)
498+ // Shall not throw a RelationNotFoundException
499+ try {
500+ removeRelation(currRelId);
501+ } catch (RelationNotFoundException exc1) {
502+ throw new RuntimeException(exc1.getMessage());
503+ }
504+ }
505+ }
506+
507+ RELATION_LOGGER.exiting(RelationService.class.getName(),
508+ "removeRelationType");
509+ return;
510+ }
511+
512+ //
513+ // Relation handling
514+ //
515+
516+ /**
517+ * Creates a simple relation (represented by a RelationSupport object) of
518+ * given relation type, and adds it in the Relation Service.
519+ * <P>Roles are initialized according to the role list provided in
520+ * parameter. The ones not initialized in this way are set to an empty
521+ * ArrayList of ObjectNames.
522+ * <P>A RelationNotification, with type RELATION_BASIC_CREATION, is sent.
523+ *
524+ * @param relationId relation identifier, to identify uniquely the relation
525+ * inside the Relation Service
526+ * @param relationTypeName name of the relation type (has to be created
527+ * in the Relation Service)
528+ * @param roleList role list to initialize roles of the relation (can
529+ * be null).
530+ *
531+ * @exception RelationServiceNotRegisteredException if the Relation
532+ * Service is not registered in the MBean Server
533+ * @exception IllegalArgumentException if null parameter, except the role
534+ * list which can be null if no role initialization
535+ * @exception RoleNotFoundException if a value is provided for a role
536+ * that does not exist in the relation type
537+ * @exception InvalidRelationIdException if relation id already used
538+ * @exception RelationTypeNotFoundException if relation type not known in
539+ * Relation Service
540+ * @exception InvalidRoleValueException if:
541+ * <P>- the same role name is used for two different roles
542+ * <P>- the number of referenced MBeans in given value is less than
543+ * expected minimum degree
544+ * <P>- the number of referenced MBeans in provided value exceeds expected
545+ * maximum degree
546+ * <P>- one referenced MBean in the value is not an Object of the MBean
547+ * class expected for that role
548+ * <P>- an MBean provided for that role does not exist
549+ */
550+ public void createRelation(String relationId,
551+ String relationTypeName,
552+ RoleList roleList)
553+ throws RelationServiceNotRegisteredException,
554+ IllegalArgumentException,
555+ RoleNotFoundException,
556+ InvalidRelationIdException,
557+ RelationTypeNotFoundException,
558+ InvalidRoleValueException {
559+
560+ // Can throw RelationServiceNotRegisteredException
561+ isActive();
562+
563+ if (relationId == null ||
564+ relationTypeName == null) {
565+ String excMsg = "Invalid parameter.";
566+ throw new IllegalArgumentException(excMsg);
567+ }
568+
569+ RELATION_LOGGER.entering(RelationService.class.getName(),
570+ "createRelation",
571+ new Object[] {relationId, relationTypeName, roleList});
572+
573+ // Creates RelationSupport object
574+ // Can throw InvalidRoleValueException
575+ RelationSupport relObj = new RelationSupport(relationId,
576+ myObjName,
577+ relationTypeName,
578+ roleList);
579+
580+ // Adds relation object as a relation into the Relation Service
581+ // Can throw RoleNotFoundException, InvalidRelationId,
582+ // RelationTypeNotFoundException, InvalidRoleValueException
583+ //
584+ // Cannot throw MBeanException
585+ addRelationInt(true,
586+ relObj,
587+ null,
588+ relationId,
589+ relationTypeName,
590+ roleList);
591+ RELATION_LOGGER.exiting(RelationService.class.getName(),
592+ "createRelation");
593+ return;
594+ }
595+
596+ /**
597+ * Adds an MBean created by the user (and registered by him in the MBean
598+ * Server) as a relation in the Relation Service.
599+ * <P>To be added as a relation, the MBean must conform to the
600+ * following:
601+ * <P>- implement the Relation interface
602+ * <P>- have for RelationService ObjectName the ObjectName of current
603+ * Relation Service
604+ * <P>- have a relation id unique and unused in current Relation Service
605+ * <P>- have for relation type a relation type created in the Relation
606+ * Service
607+ * <P>- have roles conforming to the role info provided in the relation
608+ * type.
609+ *
610+ * @param relationObjectName ObjectName of the relation MBean to be added.
611+ *
612+ * @exception IllegalArgumentException if null parameter
613+ * @exception RelationServiceNotRegisteredException if the Relation
614+ * Service is not registered in the MBean Server
615+ * @exception NoSuchMethodException If the MBean does not implement the
616+ * Relation interface
617+ * @exception InvalidRelationIdException if:
618+ * <P>- no relation identifier in MBean
619+ * <P>- the relation identifier is already used in the Relation Service
620+ * @exception InstanceNotFoundException if the MBean for given ObjectName
621+ * has not been registered
622+ * @exception InvalidRelationServiceException if:
623+ * <P>- no Relation Service name in MBean
624+ * <P>- the Relation Service name in the MBean is not the one of the
625+ * current Relation Service
626+ * @exception RelationTypeNotFoundException if:
627+ * <P>- no relation type name in MBean
628+ * <P>- the relation type name in MBean does not correspond to a relation
629+ * type created in the Relation Service
630+ * @exception InvalidRoleValueException if:
631+ * <P>- the number of referenced MBeans in a role is less than
632+ * expected minimum degree
633+ * <P>- the number of referenced MBeans in a role exceeds expected
634+ * maximum degree
635+ * <P>- one referenced MBean in the value is not an Object of the MBean
636+ * class expected for that role
637+ * <P>- an MBean provided for a role does not exist
638+ * @exception RoleNotFoundException if a value is provided for a role
639+ * that does not exist in the relation type
640+ */
641+ public void addRelation(ObjectName relationObjectName)
642+ throws IllegalArgumentException,
643+ RelationServiceNotRegisteredException,
644+ NoSuchMethodException,
645+ InvalidRelationIdException,
646+ InstanceNotFoundException,
647+ InvalidRelationServiceException,
648+ RelationTypeNotFoundException,
649+ RoleNotFoundException,
650+ InvalidRoleValueException {
651+
652+ if (relationObjectName == null) {
653+ String excMsg = "Invalid parameter.";
654+ throw new IllegalArgumentException(excMsg);
655+ }
656+
657+ RELATION_LOGGER.entering(RelationService.class.getName(),
658+ "addRelation", relationObjectName);
659+
660+ // Can throw RelationServiceNotRegisteredException
661+ isActive();
662+
663+ // Checks that the relation MBean implements the Relation interface.
664+ // It will also check that the provided ObjectName corresponds to a
665+ // registered MBean (else will throw an InstanceNotFoundException)
666+ if ((!(myMBeanServer.isInstanceOf(relationObjectName, "javax.management.relation.Relation")))) {
667+ String excMsg = "This MBean does not implement the Relation interface.";
668+ throw new NoSuchMethodException(excMsg);
669+ }
670+ // Checks there is a relation id in the relation MBean (its uniqueness
671+ // is checked in addRelationInt())
672+ // Can throw InstanceNotFoundException (but detected above)
673+ // No MBeanException as no exception raised by this method, and no
674+ // ReflectionException
675+ String relId;
676+ try {
677+ relId = (String)(myMBeanServer.getAttribute(relationObjectName,
678+ "RelationId"));
679+
680+ } catch (MBeanException exc1) {
681+ throw new RuntimeException(
682+ (exc1.getTargetException()).getMessage());
683+ } catch (ReflectionException exc2) {
684+ throw new RuntimeException(exc2.getMessage());
685+ } catch (AttributeNotFoundException exc3) {
686+ throw new RuntimeException(exc3.getMessage());
687+ }
688+
689+ if (relId == null) {
690+ String excMsg = "This MBean does not provide a relation id.";
691+ throw new InvalidRelationIdException(excMsg);
692+ }
693+ // Checks that the Relation Service where the relation MBean is
694+ // expected to be added is the current one
695+ // Can throw InstanceNotFoundException (but detected above)
696+ // No MBeanException as no exception raised by this method, no
697+ // ReflectionException
698+ ObjectName relServObjName;
699+ try {
700+ relServObjName = (ObjectName)
701+ (myMBeanServer.getAttribute(relationObjectName,
702+ "RelationServiceName"));
703+
704+ } catch (MBeanException exc1) {
705+ throw new RuntimeException(
706+ (exc1.getTargetException()).getMessage());
707+ } catch (ReflectionException exc2) {
708+ throw new RuntimeException(exc2.getMessage());
709+ } catch (AttributeNotFoundException exc3) {
710+ throw new RuntimeException(exc3.getMessage());
711+ }
712+
713+ boolean badRelServFlag = false;
714+ if (relServObjName == null) {
715+ badRelServFlag = true;
716+
717+ } else if (!(relServObjName.equals(myObjName))) {
718+ badRelServFlag = true;
719+ }
720+ if (badRelServFlag) {
721+ String excMsg = "The Relation Service referenced in the MBean is not the current one.";
722+ throw new InvalidRelationServiceException(excMsg);
723+ }
724+ // Checks that a relation type has been specified for the relation
725+ // Can throw InstanceNotFoundException (but detected above)
726+ // No MBeanException as no exception raised by this method, no
727+ // ReflectionException
728+ String relTypeName;
729+ try {
730+ relTypeName = (String)(myMBeanServer.getAttribute(relationObjectName,
731+ "RelationTypeName"));
732+
733+ } catch (MBeanException exc1) {
734+ throw new RuntimeException(
735+ (exc1.getTargetException()).getMessage());
736+ }catch (ReflectionException exc2) {
737+ throw new RuntimeException(exc2.getMessage());
738+ } catch (AttributeNotFoundException exc3) {
739+ throw new RuntimeException(exc3.getMessage());
740+ }
741+ if (relTypeName == null) {
742+ String excMsg = "No relation type provided.";
743+ throw new RelationTypeNotFoundException(excMsg);
744+ }
745+ // Retrieves all roles without considering read mode
746+ // Can throw InstanceNotFoundException (but detected above)
747+ // No MBeanException as no exception raised by this method, no
748+ // ReflectionException
749+ RoleList roleList;
750+ try {
751+ roleList = (RoleList)(myMBeanServer.invoke(relationObjectName,
752+ "retrieveAllRoles",
753+ null,
754+ null));
755+ } catch (MBeanException exc1) {
756+ throw new RuntimeException(
757+ (exc1.getTargetException()).getMessage());
758+ } catch (ReflectionException exc2) {
759+ throw new RuntimeException(exc2.getMessage());
760+ }
761+
762+ // Can throw RoleNotFoundException, InvalidRelationIdException,
763+ // RelationTypeNotFoundException, InvalidRoleValueException
764+ addRelationInt(false,
765+ null,
766+ relationObjectName,
767+ relId,
768+ relTypeName,
769+ roleList);
770+ // Adds relation MBean ObjectName in map
771+ synchronized(myRelMBeanObjName2RelIdMap) {
772+ myRelMBeanObjName2RelIdMap.put(relationObjectName, relId);
773+ }
774+
775+ // Updates flag to specify that the relation is managed by the Relation
776+ // Service
777+ // This flag and setter are inherited from RelationSupport and not parts
778+ // of the Relation interface, so may be not supported.
779+ try {
780+ myMBeanServer.setAttribute(relationObjectName,
781+ new Attribute(
782+ "RelationServiceManagementFlag",
783+ Boolean.TRUE));
784+ } catch (Exception exc) {
785+ // OK : The flag is not supported.
786+ }
787+
788+ // Updates listener information to received notification for
789+ // unregistration of this MBean
790+ List<ObjectName> newRefList = new ArrayList<ObjectName>();
791+ newRefList.add(relationObjectName);
792+ updateUnregistrationListener(newRefList, null);
793+
794+ RELATION_LOGGER.exiting(RelationService.class.getName(),
795+ "addRelation");
796+ return;
797+ }
798+
799+ /**
800+ * If the relation is represented by an MBean (created by the user and
801+ * added as a relation in the Relation Service), returns the ObjectName of
802+ * the MBean.
803+ *
804+ * @param relationId relation id identifying the relation
805+ *
806+ * @return ObjectName of the corresponding relation MBean, or null if
807+ * the relation is not an MBean.
808+ *
809+ * @exception IllegalArgumentException if null parameter
810+ * @exception RelationNotFoundException there is no relation associated
811+ * to that id
812+ */
813+ public ObjectName isRelationMBean(String relationId)
814+ throws IllegalArgumentException,
815+ RelationNotFoundException{
816+
817+ if (relationId == null) {
818+ String excMsg = "Invalid parameter.";
819+ throw new IllegalArgumentException(excMsg);
820+ }
821+
822+ RELATION_LOGGER.entering(RelationService.class.getName(),
823+ "isRelationMBean", relationId);
824+
825+ // Can throw RelationNotFoundException
826+ Object result = getRelation(relationId);
827+ if (result instanceof ObjectName) {
828+ return ((ObjectName)result);
829+ } else {
830+ return null;
831+ }
832+ }
833+
834+ /**
835+ * Returns the relation id associated to the given ObjectName if the
836+ * MBean has been added as a relation in the Relation Service.
837+ *
838+ * @param objectName ObjectName of supposed relation
839+ *
840+ * @return relation id (String) or null (if the ObjectName is not a
841+ * relation handled by the Relation Service)
842+ *
843+ * @exception IllegalArgumentException if null parameter
844+ */
845+ public String isRelation(ObjectName objectName)
846+ throws IllegalArgumentException {
847+
848+ if (objectName == null) {
849+ String excMsg = "Invalid parameter.";
850+ throw new IllegalArgumentException(excMsg);
851+ }
852+
853+ RELATION_LOGGER.entering(RelationService.class.getName(),
854+ "isRelation", objectName);
855+
856+ String result = null;
857+ synchronized(myRelMBeanObjName2RelIdMap) {
858+ String relId = myRelMBeanObjName2RelIdMap.get(objectName);
859+ if (relId != null) {
860+ result = relId;
861+ }
862+ }
863+ return result;
864+ }
865+
866+ /**
867+ * Checks if there is a relation identified in Relation Service with given
868+ * relation id.
869+ *
870+ * @param relationId relation id identifying the relation
871+ *
872+ * @return boolean: true if there is a relation, false else
873+ *
874+ * @exception IllegalArgumentException if null parameter
875+ */
876+ public Boolean hasRelation(String relationId)
877+ throws IllegalArgumentException {
878+
879+ if (relationId == null) {
880+ String excMsg = "Invalid parameter.";
881+ throw new IllegalArgumentException(excMsg);
882+ }
883+
884+ RELATION_LOGGER.entering(RelationService.class.getName(),
885+ "hasRelation", relationId);
886+
887+ try {
888+ // Can throw RelationNotFoundException
889+ Object result = getRelation(relationId);
890+ return true;
891+ } catch (RelationNotFoundException exc) {
892+ return false;
893+ }
894+ }
895+
896+ /**
897+ * Returns all the relation ids for all the relations handled by the
898+ * Relation Service.
899+ *
900+ * @return ArrayList of String
901+ */
902+ public List<String> getAllRelationIds() {
903+ List<String> result;
904+ synchronized(myRelId2ObjMap) {
905+ result = new ArrayList<String>(myRelId2ObjMap.keySet());
906+ }
907+ return result;
908+ }
909+
910+ /**
911+ * Checks if given Role can be read in a relation of the given type.
912+ *
913+ * @param roleName name of role to be checked
914+ * @param relationTypeName name of the relation type
915+ *
916+ * @return an Integer wrapping an integer corresponding to possible
917+ * problems represented as constants in RoleUnresolved:
918+ * <P>- 0 if role can be read
919+ * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME
920+ * <P>- integer corresponding to RoleStatus.ROLE_NOT_READABLE
921+ *
922+ * @exception IllegalArgumentException if null parameter
923+ * @exception RelationTypeNotFoundException if the relation type is not
924+ * known in the Relation Service
925+ */
926+ public Integer checkRoleReading(String roleName,
927+ String relationTypeName)
928+ throws IllegalArgumentException,
929+ RelationTypeNotFoundException {
930+
931+ if (roleName == null || relationTypeName == null) {
932+ String excMsg = "Invalid parameter.";
933+ throw new IllegalArgumentException(excMsg);
934+ }
935+
936+ RELATION_LOGGER.entering(RelationService.class.getName(),
937+ "checkRoleReading", new Object[] {roleName, relationTypeName});
938+
939+ Integer result;
940+
941+ // Can throw a RelationTypeNotFoundException
942+ RelationType relType = getRelationType(relationTypeName);
943+
944+ try {
945+ // Can throw a RoleInfoNotFoundException to be transformed into
946+ // returned value RoleStatus.NO_ROLE_WITH_NAME
947+ RoleInfo roleInfo = relType.getRoleInfo(roleName);
948+
949+ result = checkRoleInt(1,
950+ roleName,
951+ null,
952+ roleInfo,
953+ false);
954+
955+ } catch (RoleInfoNotFoundException exc) {
956+ result = Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
957+ }
958+
959+ RELATION_LOGGER.exiting(RelationService.class.getName(),
960+ "checkRoleReading");
961+ return result;
962+ }
963+
964+ /**
965+ * Checks if given Role can be set in a relation of given type.
966+ *
967+ * @param role role to be checked
968+ * @param relationTypeName name of relation type
969+ * @param initFlag flag to specify that the checking is done for the
970+ * initialization of a role, write access shall not be verified.
971+ *
972+ * @return an Integer wrapping an integer corresponding to possible
973+ * problems represented as constants in RoleUnresolved:
974+ * <P>- 0 if role can be set
975+ * <P>- integer corresponding to RoleStatus.NO_ROLE_WITH_NAME
976+ * <P>- integer for RoleStatus.ROLE_NOT_WRITABLE
977+ * <P>- integer for RoleStatus.LESS_THAN_MIN_ROLE_DEGREE
978+ * <P>- integer for RoleStatus.MORE_THAN_MAX_ROLE_DEGREE
979+ * <P>- integer for RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS
980+ * <P>- integer for RoleStatus.REF_MBEAN_NOT_REGISTERED
981+ *
982+ * @exception IllegalArgumentException if null parameter
983+ * @exception RelationTypeNotFoundException if unknown relation type
984+ */
985+ public Integer checkRoleWriting(Role role,
986+ String relationTypeName,
987+ Boolean initFlag)
988+ throws IllegalArgumentException,
989+ RelationTypeNotFoundException {
990+
991+ if (role == null ||
992+ relationTypeName == null ||
993+ initFlag == null) {
994+ String excMsg = "Invalid parameter.";
995+ throw new IllegalArgumentException(excMsg);
996+ }
997+
998+ RELATION_LOGGER.entering(RelationService.class.getName(),
999+ "checkRoleWriting",
1000+ new Object[] {role, relationTypeName, initFlag});
1001+
1002+ // Can throw a RelationTypeNotFoundException
1003+ RelationType relType = getRelationType(relationTypeName);
1004+
1005+ String roleName = role.getRoleName();
1006+ List<ObjectName> roleValue = role.getRoleValue();
1007+ boolean writeChkFlag = true;
1008+ if (initFlag.booleanValue()) {
1009+ writeChkFlag = false;
1010+ }
1011+
1012+ RoleInfo roleInfo;
1013+ try {
1014+ roleInfo = relType.getRoleInfo(roleName);
1015+ } catch (RoleInfoNotFoundException exc) {
1016+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1017+ "checkRoleWriting");
1018+ return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
1019+ }
1020+
1021+ Integer result = checkRoleInt(2,
1022+ roleName,
1023+ roleValue,
1024+ roleInfo,
1025+ writeChkFlag);
1026+
1027+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1028+ "checkRoleWriting");
1029+ return result;
1030+ }
1031+
1032+ /**
1033+ * Sends a notification (RelationNotification) for a relation creation.
1034+ * The notification type is:
1035+ * <P>- RelationNotification.RELATION_BASIC_CREATION if the relation is an
1036+ * object internal to the Relation Service
1037+ * <P>- RelationNotification.RELATION_MBEAN_CREATION if the relation is a
1038+ * MBean added as a relation.
1039+ * <P>The source object is the Relation Service itself.
1040+ * <P>It is called in Relation Service createRelation() and
1041+ * addRelation() methods.
1042+ *
1043+ * @param relationId relation identifier of the updated relation
1044+ *
1045+ * @exception IllegalArgumentException if null parameter
1046+ * @exception RelationNotFoundException if there is no relation for given
1047+ * relation id
1048+ */
1049+ public void sendRelationCreationNotification(String relationId)
1050+ throws IllegalArgumentException,
1051+ RelationNotFoundException {
1052+
1053+ if (relationId == null) {
1054+ String excMsg = "Invalid parameter.";
1055+ throw new IllegalArgumentException(excMsg);
1056+ }
1057+
1058+ RELATION_LOGGER.entering(RelationService.class.getName(),
1059+ "sendRelationCreationNotification", relationId);
1060+
1061+ // Message
1062+ StringBuilder ntfMsg = new StringBuilder("Creation of relation ");
1063+ ntfMsg.append(relationId);
1064+
1065+ // Can throw RelationNotFoundException
1066+ sendNotificationInt(1,
1067+ ntfMsg.toString(),
1068+ relationId,
1069+ null,
1070+ null,
1071+ null,
1072+ null);
1073+
1074+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1075+ "sendRelationCreationNotification");
1076+ return;
1077+ }
1078+
1079+ /**
1080+ * Sends a notification (RelationNotification) for a role update in the
1081+ * given relation. The notification type is:
1082+ * <P>- RelationNotification.RELATION_BASIC_UPDATE if the relation is an
1083+ * object internal to the Relation Service
1084+ * <P>- RelationNotification.RELATION_MBEAN_UPDATE if the relation is a
1085+ * MBean added as a relation.
1086+ * <P>The source object is the Relation Service itself.
1087+ * <P>It is called in relation MBean setRole() (for given role) and
1088+ * setRoles() (for each role) methods (implementation provided in
1089+ * RelationSupport class).
1090+ * <P>It is also called in Relation Service setRole() (for given role) and
1091+ * setRoles() (for each role) methods.
1092+ *
1093+ * @param relationId relation identifier of the updated relation
1094+ * @param newRole new role (name and new value)
1095+ * @param oldValue old role value (List of ObjectName objects)
1096+ *
1097+ * @exception IllegalArgumentException if null parameter
1098+ * @exception RelationNotFoundException if there is no relation for given
1099+ * relation id
1100+ */
1101+ public void sendRoleUpdateNotification(String relationId,
1102+ Role newRole,
1103+ List<ObjectName> oldValue)
1104+ throws IllegalArgumentException,
1105+ RelationNotFoundException {
1106+
1107+ if (relationId == null ||
1108+ newRole == null ||
1109+ oldValue == null) {
1110+ String excMsg = "Invalid parameter.";
1111+ throw new IllegalArgumentException(excMsg);
1112+ }
1113+
1114+ if (!(oldValue instanceof ArrayList<?>))
1115+ oldValue = new ArrayList<ObjectName>(oldValue);
1116+
1117+ RELATION_LOGGER.entering(RelationService.class.getName(),
1118+ "sendRoleUpdateNotification",
1119+ new Object[] {relationId, newRole, oldValue});
1120+
1121+ String roleName = newRole.getRoleName();
1122+ List<ObjectName> newRoleVal = newRole.getRoleValue();
1123+
1124+ // Message
1125+ String newRoleValString = Role.roleValueToString(newRoleVal);
1126+ String oldRoleValString = Role.roleValueToString(oldValue);
1127+ StringBuilder ntfMsg = new StringBuilder("Value of role ");
1128+ ntfMsg.append(roleName);
1129+ ntfMsg.append(" has changed\nOld value:\n");
1130+ ntfMsg.append(oldRoleValString);
1131+ ntfMsg.append("\nNew value:\n");
1132+ ntfMsg.append(newRoleValString);
1133+
1134+ // Can throw a RelationNotFoundException
1135+ sendNotificationInt(2,
1136+ ntfMsg.toString(),
1137+ relationId,
1138+ null,
1139+ roleName,
1140+ newRoleVal,
1141+ oldValue);
1142+
1143+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1144+ "sendRoleUpdateNotification");
1145+ }
1146+
1147+ /**
1148+ * Sends a notification (RelationNotification) for a relation removal.
1149+ * The notification type is:
1150+ * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation is an
1151+ * object internal to the Relation Service
1152+ * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is a
1153+ * MBean added as a relation.
1154+ * <P>The source object is the Relation Service itself.
1155+ * <P>It is called in Relation Service removeRelation() method.
1156+ *
1157+ * @param relationId relation identifier of the updated relation
1158+ * @param unregMBeanList List of ObjectNames of MBeans expected
1159+ * to be unregistered due to relation removal (can be null)
1160+ *
1161+ * @exception IllegalArgumentException if null parameter
1162+ * @exception RelationNotFoundException if there is no relation for given
1163+ * relation id
1164+ */
1165+ public void sendRelationRemovalNotification(String relationId,
1166+ List<ObjectName> unregMBeanList)
1167+ throws IllegalArgumentException,
1168+ RelationNotFoundException {
1169+
1170+ if (relationId == null) {
1171+ String excMsg = "Invalid parameter";
1172+ throw new IllegalArgumentException(excMsg);
1173+ }
1174+
1175+ RELATION_LOGGER.entering(RelationService.class.getName(),
1176+ "sendRelationRemovalNotification",
1177+ new Object[] {relationId, unregMBeanList});
1178+
1179+ // Can throw RelationNotFoundException
1180+ sendNotificationInt(3,
1181+ "Removal of relation " + relationId,
1182+ relationId,
1183+ unregMBeanList,
1184+ null,
1185+ null,
1186+ null);
1187+
1188+
1189+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1190+ "sendRelationRemovalNotification");
1191+ return;
1192+ }
1193+
1194+ /**
1195+ * Handles update of the Relation Service role map for the update of given
1196+ * role in given relation.
1197+ * <P>It is called in relation MBean setRole() (for given role) and
1198+ * setRoles() (for each role) methods (implementation provided in
1199+ * RelationSupport class).
1200+ * <P>It is also called in Relation Service setRole() (for given role) and
1201+ * setRoles() (for each role) methods.
1202+ * <P>To allow the Relation Service to maintain the consistency (in case
1203+ * of MBean unregistration) and to be able to perform queries, this method
1204+ * must be called when a role is updated.
1205+ *
1206+ * @param relationId relation identifier of the updated relation
1207+ * @param newRole new role (name and new value)
1208+ * @param oldValue old role value (List of ObjectName objects)
1209+ *
1210+ * @exception IllegalArgumentException if null parameter
1211+ * @exception RelationServiceNotRegisteredException if the Relation
1212+ * Service is not registered in the MBean Server
1213+ * @exception RelationNotFoundException if no relation for given id.
1214+ */
1215+ public void updateRoleMap(String relationId,
1216+ Role newRole,
1217+ List<ObjectName> oldValue)
1218+ throws IllegalArgumentException,
1219+ RelationServiceNotRegisteredException,
1220+ RelationNotFoundException {
1221+
1222+ if (relationId == null ||
1223+ newRole == null ||
1224+ oldValue == null) {
1225+ String excMsg = "Invalid parameter.";
1226+ throw new IllegalArgumentException(excMsg);
1227+ }
1228+
1229+ RELATION_LOGGER.entering(RelationService.class.getName(),
1230+ "updateRoleMap", new Object[] {relationId, newRole, oldValue});
1231+
1232+ // Can throw RelationServiceNotRegisteredException
1233+ isActive();
1234+
1235+ // Verifies the relation has been added in the Relation Service
1236+ // Can throw a RelationNotFoundException
1237+ Object result = getRelation(relationId);
1238+
1239+ String roleName = newRole.getRoleName();
1240+ List<ObjectName> newRoleValue = newRole.getRoleValue();
1241+ // Note: no need to test if oldValue not null before cloning,
1242+ // tested above.
1243+ List<ObjectName> oldRoleValue =
1244+ new ArrayList<ObjectName>(oldValue);
1245+
1246+ // List of ObjectNames of new referenced MBeans
1247+ List<ObjectName> newRefList = new ArrayList<ObjectName>();
1248+
1249+ for (ObjectName currObjName : newRoleValue) {
1250+
1251+ // Checks if this ObjectName was already present in old value
1252+ // Note: use copy (oldRoleValue) instead of original
1253+ // oldValue to speed up, as oldRoleValue is decreased
1254+ // by removing unchanged references :)
1255+ int currObjNamePos = oldRoleValue.indexOf(currObjName);
1256+
1257+ if (currObjNamePos == -1) {
1258+ // New reference to an ObjectName
1259+
1260+ // Stores this reference into map
1261+ // Returns true if new reference, false if MBean already
1262+ // referenced
1263+ boolean isNewFlag = addNewMBeanReference(currObjName,
1264+ relationId,
1265+ roleName);
1266+
1267+ if (isNewFlag) {
1268+ // Adds it into list of new reference
1269+ newRefList.add(currObjName);
1270+ }
1271+
1272+ } else {
1273+ // MBean was already referenced in old value
1274+
1275+ // Removes it from old value (local list) to ignore it when
1276+ // looking for remove MBean references
1277+ oldRoleValue.remove(currObjNamePos);
1278+ }
1279+ }
1280+
1281+ // List of ObjectNames of MBeans no longer referenced
1282+ List<ObjectName> obsRefList = new ArrayList<ObjectName>();
1283+
1284+ // Each ObjectName remaining in oldRoleValue is an ObjectName no longer
1285+ // referenced in new value
1286+ for (ObjectName currObjName : oldRoleValue) {
1287+ // Removes MBean reference from map
1288+ // Returns true if the MBean is no longer referenced in any
1289+ // relation
1290+ boolean noLongerRefFlag = removeMBeanReference(currObjName,
1291+ relationId,
1292+ roleName,
1293+ false);
1294+
1295+ if (noLongerRefFlag) {
1296+ // Adds it into list of references to be removed
1297+ obsRefList.add(currObjName);
1298+ }
1299+ }
1300+
1301+ // To avoid having one listener per ObjectName of referenced MBean,
1302+ // and to increase performances, there is only one listener recording
1303+ // all ObjectNames of interest
1304+ updateUnregistrationListener(newRefList, obsRefList);
1305+
1306+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1307+ "updateRoleMap");
1308+ return;
1309+ }
1310+
1311+ /**
1312+ * Removes given relation from the Relation Service.
1313+ * <P>A RelationNotification notification is sent, its type being:
1314+ * <P>- RelationNotification.RELATION_BASIC_REMOVAL if the relation was
1315+ * only internal to the Relation Service
1316+ * <P>- RelationNotification.RELATION_MBEAN_REMOVAL if the relation is
1317+ * registered as an MBean.
1318+ * <P>For MBeans referenced in such relation, nothing will be done,
1319+ *
1320+ * @param relationId relation id of the relation to be removed
1321+ *
1322+ * @exception RelationServiceNotRegisteredException if the Relation
1323+ * Service is not registered in the MBean Server
1324+ * @exception IllegalArgumentException if null parameter
1325+ * @exception RelationNotFoundException if no relation corresponding to
1326+ * given relation id
1327+ */
1328+ public void removeRelation(String relationId)
1329+ throws RelationServiceNotRegisteredException,
1330+ IllegalArgumentException,
1331+ RelationNotFoundException {
1332+
1333+ // Can throw RelationServiceNotRegisteredException
1334+ isActive();
1335+
1336+ if (relationId == null) {
1337+ String excMsg = "Invalid parameter.";
1338+ throw new IllegalArgumentException(excMsg);
1339+ }
1340+
1341+ RELATION_LOGGER.entering(RelationService.class.getName(),
1342+ "removeRelation", relationId);
1343+
1344+ // Checks there is a relation with this id
1345+ // Can throw RelationNotFoundException
1346+ Object result = getRelation(relationId);
1347+
1348+ // Removes it from listener filter
1349+ if (result instanceof ObjectName) {
1350+ List<ObjectName> obsRefList = new ArrayList<ObjectName>();
1351+ obsRefList.add((ObjectName)result);
1352+ // Can throw a RelationServiceNotRegisteredException
1353+ updateUnregistrationListener(null, obsRefList);
1354+ }
1355+
1356+ // Sends a notification
1357+ // Note: has to be done FIRST as needs the relation to be still in the
1358+ // Relation Service
1359+ // No RelationNotFoundException as checked above
1360+
1361+ // Revisit [cebro] Handle CIM "Delete" and "IfDeleted" qualifiers:
1362+ // deleting the relation can mean to delete referenced MBeans. In
1363+ // that case, MBeans to be unregistered are put in a list sent along
1364+ // with the notification below
1365+
1366+ // Can throw a RelationNotFoundException (but detected above)
1367+ sendRelationRemovalNotification(relationId, null);
1368+
1369+ // Removes the relation from various internal maps
1370+
1371+ // - MBean reference map
1372+ // Retrieves the MBeans referenced in this relation
1373+ // Note: here we cannot use removeMBeanReference() because it would
1374+ // require to know the MBeans referenced in the relation. For
1375+ // that it would be necessary to call 'getReferencedMBeans()'
1376+ // on the relation itself. Ok if it is an internal one, but if
1377+ // it is an MBean, it is possible it is already unregistered, so
1378+ // not available through the MBean Server.
1379+ List<ObjectName> refMBeanList = new ArrayList<ObjectName>();
1380+ // List of MBeans no longer referenced in any relation, to be
1381+ // removed fom the map
1382+ List<ObjectName> nonRefObjNameList = new ArrayList<ObjectName>();
1383+
1384+ synchronized(myRefedMBeanObjName2RelIdsMap) {
1385+
1386+ for (ObjectName currRefObjName :
1387+ myRefedMBeanObjName2RelIdsMap.keySet()) {
1388+
1389+ // Retrieves relations where the MBean is referenced
1390+ Map<String,List<String>> relIdMap =
1391+ myRefedMBeanObjName2RelIdsMap.get(currRefObjName);
1392+
1393+ if (relIdMap.containsKey(relationId)) {
1394+ relIdMap.remove(relationId);
1395+ refMBeanList.add(currRefObjName);
1396+ }
1397+
1398+ if (relIdMap.isEmpty()) {
1399+ // MBean no longer referenced
1400+ // Note: do not remove it here because pointed by the
1401+ // iterator!
1402+ nonRefObjNameList.add(currRefObjName);
1403+ }
1404+ }
1405+
1406+ // Cleans MBean reference map by removing MBeans no longer
1407+ // referenced
1408+ for (ObjectName currRefObjName : nonRefObjNameList) {
1409+ myRefedMBeanObjName2RelIdsMap.remove(currRefObjName);
1410+ }
1411+ }
1412+
1413+ // - Relation id to object map
1414+ synchronized(myRelId2ObjMap) {
1415+ myRelId2ObjMap.remove(relationId);
1416+ }
1417+
1418+ if (result instanceof ObjectName) {
1419+ // - ObjectName to relation id map
1420+ synchronized(myRelMBeanObjName2RelIdMap) {
1421+ myRelMBeanObjName2RelIdMap.remove((ObjectName)result);
1422+ }
1423+ }
1424+
1425+ // Relation id to relation type name map
1426+ // First retrieves the relation type name
1427+ String relTypeName;
1428+ synchronized(myRelId2RelTypeMap) {
1429+ relTypeName = myRelId2RelTypeMap.get(relationId);
1430+ myRelId2RelTypeMap.remove(relationId);
1431+ }
1432+ // - Relation type name to relation id map
1433+ synchronized(myRelType2RelIdsMap) {
1434+ List<String> relIdList = myRelType2RelIdsMap.get(relTypeName);
1435+ if (relIdList != null) {
1436+ // Can be null if called from removeRelationType()
1437+ relIdList.remove(relationId);
1438+ if (relIdList.isEmpty()) {
1439+ // No other relation of that type
1440+ myRelType2RelIdsMap.remove(relTypeName);
1441+ }
1442+ }
1443+ }
1444+
1445+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1446+ "removeRelation");
1447+ return;
1448+ }
1449+
1450+ /**
1451+ * Purges the relations.
1452+ *
1453+ * <P>Depending on the purgeFlag value, this method is either called
1454+ * automatically when a notification is received for the unregistration of
1455+ * an MBean referenced in a relation (if the flag is set to true), or not
1456+ * (if the flag is set to false).
1457+ * <P>In that case it is up to the user to call it to maintain the
1458+ * consistency of the relations. To be kept in mind that if an MBean is
1459+ * unregistered and the purge not done immediately, if the ObjectName is
1460+ * reused and assigned to another MBean referenced in a relation, calling
1461+ * manually this purgeRelations() method will cause trouble, as will
1462+ * consider the ObjectName as corresponding to the unregistered MBean, not
1463+ * seeing the new one.
1464+ *
1465+ * <P>The behavior depends on the cardinality of the role where the
1466+ * unregistered MBean is referenced:
1467+ * <P>- if removing one MBean reference in the role makes its number of
1468+ * references less than the minimum degree, the relation has to be removed.
1469+ * <P>- if the remaining number of references after removing the MBean
1470+ * reference is still in the cardinality range, keep the relation and
1471+ * update it calling its handleMBeanUnregistration() callback.
1472+ *
1473+ * @exception RelationServiceNotRegisteredException if the Relation
1474+ * Service is not registered in the MBean Server.
1475+ */
1476+ public void purgeRelations()
1477+ throws RelationServiceNotRegisteredException {
1478+
1479+ RELATION_LOGGER.entering(RelationService.class.getName(),
1480+ "purgeRelations");
1481+
1482+ // Can throw RelationServiceNotRegisteredException
1483+ isActive();
1484+
1485+ // Revisit [cebro] Handle the CIM "Delete" and "IfDeleted" qualifier:
1486+ // if the unregistered MBean has the "IfDeleted" qualifier,
1487+ // possible that the relation itself or other referenced MBeans
1488+ // have to be removed (then a notification would have to be sent
1489+ // to inform that they should be unregistered.
1490+
1491+
1492+ // Clones the list of notifications to be able to still receive new
1493+ // notifications while proceeding those ones
1494+ List<MBeanServerNotification> localUnregNtfList;
1495+ synchronized(myRefedMBeanObjName2RelIdsMap) {
1496+ localUnregNtfList =
1497+ new ArrayList<MBeanServerNotification>(myUnregNtfList);
1498+ // Resets list
1499+ myUnregNtfList = new ArrayList<MBeanServerNotification>();
1500+ }
1501+
1502+
1503+ // Updates the listener filter to avoid receiving notifications for
1504+ // those MBeans again
1505+ // Makes also a local "myRefedMBeanObjName2RelIdsMap" map, mapping
1506+ // ObjectName -> relId -> roles, to remove the MBean from the global
1507+ // map
1508+ // List of references to be removed from the listener filter
1509+ List<ObjectName> obsRefList = new ArrayList<ObjectName>();
1510+ // Map including ObjectNames for unregistered MBeans, with
1511+ // referencing relation ids and roles
1512+ Map<ObjectName,Map<String,List<String>>> localMBean2RelIdMap =
1513+ new HashMap<ObjectName,Map<String,List<String>>>();
1514+
1515+ synchronized(myRefedMBeanObjName2RelIdsMap) {
1516+ for (MBeanServerNotification currNtf : localUnregNtfList) {
1517+
1518+ ObjectName unregMBeanName = currNtf.getMBeanName();
1519+
1520+ // Adds the unregsitered MBean in the list of references to
1521+ // remove from the listener filter
1522+ obsRefList.add(unregMBeanName);
1523+
1524+ // Retrieves the associated map of relation ids and roles
1525+ Map<String,List<String>> relIdMap =
1526+ myRefedMBeanObjName2RelIdsMap.get(unregMBeanName);
1527+ localMBean2RelIdMap.put(unregMBeanName, relIdMap);
1528+
1529+ myRefedMBeanObjName2RelIdsMap.remove(unregMBeanName);
1530+ }
1531+ }
1532+
1533+ // Updates the listener
1534+ // Can throw RelationServiceNotRegisteredException
1535+ updateUnregistrationListener(null, obsRefList);
1536+
1537+ for (MBeanServerNotification currNtf : localUnregNtfList) {
1538+
1539+ ObjectName unregMBeanName = currNtf.getMBeanName();
1540+
1541+ // Retrieves the relations where the MBean is referenced
1542+ Map<String,List<String>> localRelIdMap =
1543+ localMBean2RelIdMap.get(unregMBeanName);
1544+
1545+ // List of relation ids where the unregistered MBean is
1546+ // referenced
1547+ for (Map.Entry<String,List<String>> currRel :
1548+ localRelIdMap.entrySet()) {
1549+ final String currRelId = currRel.getKey();
1550+ // List of roles of the relation where the MBean is
1551+ // referenced
1552+ List<String> localRoleNameList = currRel.getValue();
1553+
1554+ // Checks if the relation has to be removed or not,
1555+ // regarding expected minimum role cardinality and current
1556+ // number of references after removal of the current one
1557+ // If the relation is kept, calls
1558+ // handleMBeanUnregistration() callback of the relation to
1559+ // update it
1560+ //
1561+ // Can throw RelationServiceNotRegisteredException
1562+ //
1563+ // Shall not throw RelationNotFoundException,
1564+ // RoleNotFoundException, MBeanException
1565+ try {
1566+ handleReferenceUnregistration(currRelId,
1567+ unregMBeanName,
1568+ localRoleNameList);
1569+ } catch (RelationNotFoundException exc1) {
1570+ throw new RuntimeException(exc1.getMessage());
1571+ } catch (RoleNotFoundException exc2) {
1572+ throw new RuntimeException(exc2.getMessage());
1573+ }
1574+ }
1575+ }
1576+
1577+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1578+ "purgeRelations");
1579+ return;
1580+ }
1581+
1582+ /**
1583+ * Retrieves the relations where a given MBean is referenced.
1584+ * <P>This corresponds to the CIM "References" and "ReferenceNames"
1585+ * operations.
1586+ *
1587+ * @param mbeanName ObjectName of MBean
1588+ * @param relationTypeName can be null; if specified, only the relations
1589+ * of that type will be considered in the search. Else all relation types
1590+ * are considered.
1591+ * @param roleName can be null; if specified, only the relations
1592+ * where the MBean is referenced in that role will be returned. Else all
1593+ * roles are considered.
1594+ *
1595+ * @return an HashMap, where the keys are the relation ids of the relations
1596+ * where the MBean is referenced, and the value is, for each key,
1597+ * an ArrayList of role names (as an MBean can be referenced in several
1598+ * roles in the same relation).
1599+ *
1600+ * @exception IllegalArgumentException if null parameter
1601+ */
1602+ public Map<String,List<String>>
1603+ findReferencingRelations(ObjectName mbeanName,
1604+ String relationTypeName,
1605+ String roleName)
1606+ throws IllegalArgumentException {
1607+
1608+ if (mbeanName == null) {
1609+ String excMsg = "Invalid parameter.";
1610+ throw new IllegalArgumentException(excMsg);
1611+ }
1612+
1613+ RELATION_LOGGER.entering(RelationService.class.getName(),
1614+ "findReferencingRelations",
1615+ new Object[] {mbeanName, relationTypeName, roleName});
1616+
1617+ Map<String,List<String>> result = new HashMap<String,List<String>>();
1618+
1619+ synchronized(myRefedMBeanObjName2RelIdsMap) {
1620+
1621+ // Retrieves the relations referencing the MBean
1622+ Map<String,List<String>> relId2RoleNamesMap =
1623+ myRefedMBeanObjName2RelIdsMap.get(mbeanName);
1624+
1625+ if (relId2RoleNamesMap != null) {
1626+
1627+ // Relation Ids where the MBean is referenced
1628+ Set<String> allRelIdSet = relId2RoleNamesMap.keySet();
1629+
1630+ // List of relation ids of interest regarding the selected
1631+ // relation type
1632+ List<String> relIdList;
1633+ if (relationTypeName == null) {
1634+ // Considers all relations
1635+ relIdList = new ArrayList<String>(allRelIdSet);
1636+
1637+ } else {
1638+
1639+ relIdList = new ArrayList<String>();
1640+
1641+ // Considers only the relation ids for relations of given
1642+ // type
1643+ for (String currRelId : allRelIdSet) {
1644+
1645+ // Retrieves its relation type
1646+ String currRelTypeName;
1647+ synchronized(myRelId2RelTypeMap) {
1648+ currRelTypeName =
1649+ myRelId2RelTypeMap.get(currRelId);
1650+ }
1651+
1652+ if (currRelTypeName.equals(relationTypeName)) {
1653+
1654+ relIdList.add(currRelId);
1655+
1656+ }
1657+ }
1658+ }
1659+
1660+ // Now looks at the roles where the MBean is expected to be
1661+ // referenced
1662+
1663+ for (String currRelId : relIdList) {
1664+ // Retrieves list of role names where the MBean is
1665+ // referenced
1666+ List<String> currRoleNameList =
1667+ relId2RoleNamesMap.get(currRelId);
1668+
1669+ if (roleName == null) {
1670+ // All roles to be considered
1671+ // Note: no need to test if list not null before
1672+ // cloning, MUST be not null else bug :(
1673+ result.put(currRelId,
1674+ new ArrayList<String>(currRoleNameList));
1675+
1676+ } else if (currRoleNameList.contains(roleName)) {
1677+ // Filters only the relations where the MBean is
1678+ // referenced in // given role
1679+ List<String> dummyList = new ArrayList<String>();
1680+ dummyList.add(roleName);
1681+ result.put(currRelId, dummyList);
1682+ }
1683+ }
1684+ }
1685+ }
1686+
1687+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1688+ "findReferencingRelations");
1689+ return result;
1690+ }
1691+
1692+ /**
1693+ * Retrieves the MBeans associated to given one in a relation.
1694+ * <P>This corresponds to CIM Associators and AssociatorNames operations.
1695+ *
1696+ * @param mbeanName ObjectName of MBean
1697+ * @param relationTypeName can be null; if specified, only the relations
1698+ * of that type will be considered in the search. Else all
1699+ * relation types are considered.
1700+ * @param roleName can be null; if specified, only the relations
1701+ * where the MBean is referenced in that role will be considered. Else all
1702+ * roles are considered.
1703+ *
1704+ * @return an HashMap, where the keys are the ObjectNames of the MBeans
1705+ * associated to given MBean, and the value is, for each key, an ArrayList
1706+ * of the relation ids of the relations where the key MBean is
1707+ * associated to given one (as they can be associated in several different
1708+ * relations).
1709+ *
1710+ * @exception IllegalArgumentException if null parameter
1711+ */
1712+ public Map<ObjectName,List<String>>
1713+ findAssociatedMBeans(ObjectName mbeanName,
1714+ String relationTypeName,
1715+ String roleName)
1716+ throws IllegalArgumentException {
1717+
1718+ if (mbeanName == null) {
1719+ String excMsg = "Invalid parameter.";
1720+ throw new IllegalArgumentException(excMsg);
1721+ }
1722+
1723+ RELATION_LOGGER.entering(RelationService.class.getName(),
1724+ "findAssociatedMBeans",
1725+ new Object[] {mbeanName, relationTypeName, roleName});
1726+
1727+ // Retrieves the map <relation id> -> <role names> for those
1728+ // criterias
1729+ Map<String,List<String>> relId2RoleNamesMap =
1730+ findReferencingRelations(mbeanName,
1731+ relationTypeName,
1732+ roleName);
1733+
1734+ Map<ObjectName,List<String>> result =
1735+ new HashMap<ObjectName,List<String>>();
1736+
1737+ for (String currRelId : relId2RoleNamesMap.keySet()) {
1738+
1739+ // Retrieves ObjectNames of MBeans referenced in this relation
1740+ //
1741+ // Shall not throw a RelationNotFoundException if incorrect status
1742+ // of maps :(
1743+ Map<ObjectName,List<String>> objName2RoleNamesMap;
1744+ try {
1745+ objName2RoleNamesMap = getReferencedMBeans(currRelId);
1746+ } catch (RelationNotFoundException exc) {
1747+ throw new RuntimeException(exc.getMessage());
1748+ }
1749+
1750+ // For each MBean associated to given one in a relation, adds the
1751+ // association <ObjectName> -> <relation id> into result map
1752+ for (ObjectName currObjName : objName2RoleNamesMap.keySet()) {
1753+
1754+ if (!(currObjName.equals(mbeanName))) {
1755+
1756+ // Sees if this MBean is already associated to the given
1757+ // one in another relation
1758+ List<String> currRelIdList = result.get(currObjName);
1759+ if (currRelIdList == null) {
1760+
1761+ currRelIdList = new ArrayList<String>();
1762+ currRelIdList.add(currRelId);
1763+ result.put(currObjName, currRelIdList);
1764+
1765+ } else {
1766+ currRelIdList.add(currRelId);
1767+ }
1768+ }
1769+ }
1770+ }
1771+
1772+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1773+ "findAssociatedMBeans");
1774+ return result;
1775+ }
1776+
1777+ /**
1778+ * Returns the relation ids for relations of the given type.
1779+ *
1780+ * @param relationTypeName relation type name
1781+ *
1782+ * @return an ArrayList of relation ids.
1783+ *
1784+ * @exception IllegalArgumentException if null parameter
1785+ * @exception RelationTypeNotFoundException if there is no relation type
1786+ * with that name.
1787+ */
1788+ public List<String> findRelationsOfType(String relationTypeName)
1789+ throws IllegalArgumentException,
1790+ RelationTypeNotFoundException {
1791+
1792+ if (relationTypeName == null) {
1793+ String excMsg = "Invalid parameter.";
1794+ throw new IllegalArgumentException(excMsg);
1795+ }
1796+
1797+ RELATION_LOGGER.entering(RelationService.class.getName(),
1798+ "findRelationsOfType");
1799+
1800+ // Can throw RelationTypeNotFoundException
1801+ RelationType relType = getRelationType(relationTypeName);
1802+
1803+ List<String> result;
1804+ synchronized(myRelType2RelIdsMap) {
1805+ List<String> result1 = myRelType2RelIdsMap.get(relationTypeName);
1806+ if (result1 == null)
1807+ result = new ArrayList<String>();
1808+ else
1809+ result = new ArrayList<String>(result1);
1810+ }
1811+
1812+ RELATION_LOGGER.exiting(RelationService.class.getName(),
1813+ "findRelationsOfType");
1814+ return result;
1815+ }
1816+
1817+ /**
1818+ * Retrieves role value for given role name in given relation.
1819+ *
1820+ * @param relationId relation id
1821+ * @param roleName name of role
1822+ *
1823+ * @return the ArrayList of ObjectName objects being the role value
1824+ *
1825+ * @exception RelationServiceNotRegisteredException if the Relation
1826+ * Service is not registered
1827+ * @exception IllegalArgumentException if null parameter
1828+ * @exception RelationNotFoundException if no relation with given id
1829+ * @exception RoleNotFoundException if:
1830+ * <P>- there is no role with given name
1831+ * <P>or
1832+ * <P>- the role is not readable.
1833+ *
1834+ * @see #setRole
1835+ */
1836+ public List<ObjectName> getRole(String relationId,
1837+ String roleName)
1838+ throws RelationServiceNotRegisteredException,
1839+ IllegalArgumentException,
1840+ RelationNotFoundException,
1841+ RoleNotFoundException {
1842+
1843+ if (relationId == null || roleName == null) {
1844+ String excMsg = "Invalid parameter.";
1845+ throw new IllegalArgumentException(excMsg);
1846+ }
1847+
1848+ RELATION_LOGGER.entering(RelationService.class.getName(),
1849+ "getRole", new Object[] {relationId, roleName});
1850+
1851+ // Can throw RelationServiceNotRegisteredException
1852+ isActive();
1853+
1854+ // Can throw a RelationNotFoundException
1855+ Object relObj = getRelation(relationId);
1856+
1857+ List<ObjectName> result;
1858+
1859+ if (relObj instanceof RelationSupport) {
1860+ // Internal relation
1861+ // Can throw RoleNotFoundException
1862+ result = cast(
1863+ ((RelationSupport)relObj).getRoleInt(roleName,
1864+ true,
1865+ this,
1866+ false));
1867+
1868+ } else {
1869+ // Relation MBean
1870+ Object[] params = new Object[1];
1871+ params[0] = roleName;
1872+ String[] signature = new String[1];
1873+ signature[0] = "java.lang.String";
1874+ // Can throw MBeanException wrapping a RoleNotFoundException:
1875+ // throw wrapped exception
1876+ //
1877+ // Shall not throw InstanceNotFoundException or ReflectionException
1878+ try {
1879+ List<ObjectName> invokeResult = cast(
1880+ myMBeanServer.invoke(((ObjectName)relObj),
1881+ "getRole",
1882+ params,
1883+ signature));
1884+ if (invokeResult == null || invokeResult instanceof ArrayList<?>)
1885+ result = invokeResult;
1886+ else
1887+ result = new ArrayList<ObjectName>(invokeResult);
1888+ } catch (InstanceNotFoundException exc1) {
1889+ throw new RuntimeException(exc1.getMessage());
1890+ } catch (ReflectionException exc2) {
1891+ throw new RuntimeException(exc2.getMessage());
1892+ } catch (MBeanException exc3) {
1893+ Exception wrappedExc = exc3.getTargetException();
1894+ if (wrappedExc instanceof RoleNotFoundException) {
1895+ throw ((RoleNotFoundException)wrappedExc);
1896+ } else {
1897+ throw new RuntimeException(wrappedExc.getMessage());
1898+ }
1899+ }
1900+ }
1901+
1902+ RELATION_LOGGER.exiting(RelationService.class.getName(), "getRole");
1903+ return result;
1904+ }
1905+
1906+ /**
1907+ * Retrieves values of roles with given names in given relation.
1908+ *
1909+ * @param relationId relation id
1910+ * @param roleNameArray array of names of roles to be retrieved
1911+ *
1912+ * @return a RoleResult object, including a RoleList (for roles
1913+ * successfully retrieved) and a RoleUnresolvedList (for roles not
1914+ * retrieved).
1915+ *
1916+ * @exception RelationServiceNotRegisteredException if the Relation
1917+ * Service is not registered in the MBean Server
1918+ * @exception IllegalArgumentException if null parameter
1919+ * @exception RelationNotFoundException if no relation with given id
1920+ *
1921+ * @see #setRoles
1922+ */
1923+ public RoleResult getRoles(String relationId,
1924+ String[] roleNameArray)
1925+ throws RelationServiceNotRegisteredException,
1926+ IllegalArgumentException,
1927+ RelationNotFoundException {
1928+
1929+ if (relationId == null || roleNameArray == null) {
1930+ String excMsg = "Invalid parameter.";
1931+ throw new IllegalArgumentException(excMsg);
1932+ }
1933+
1934+ RELATION_LOGGER.entering(RelationService.class.getName(),
1935+ "getRoles", relationId);
1936+
1937+ // Can throw RelationServiceNotRegisteredException
1938+ isActive();
1939+
1940+ // Can throw a RelationNotFoundException
1941+ Object relObj = getRelation(relationId);
1942+
1943+ RoleResult result;
1944+
1945+ if (relObj instanceof RelationSupport) {
1946+ // Internal relation
1947+ result = ((RelationSupport)relObj).getRolesInt(roleNameArray,
1948+ true,
1949+ this);
1950+ } else {
1951+ // Relation MBean
1952+ Object[] params = new Object[1];
1953+ params[0] = roleNameArray;
1954+ String[] signature = new String[1];
1955+ try {
1956+ signature[0] = (roleNameArray.getClass()).getName();
1957+ } catch (Exception exc) {
1958+ // OK : This is an array of java.lang.String
1959+ // so this should never happen...
1960+ }
1961+ // Shall not throw InstanceNotFoundException, ReflectionException
1962+ // or MBeanException
1963+ try {
1964+ result = (RoleResult)
1965+ (myMBeanServer.invoke(((ObjectName)relObj),
1966+ "getRoles",
1967+ params,
1968+ signature));
1969+ } catch (InstanceNotFoundException exc1) {
1970+ throw new RuntimeException(exc1.getMessage());
1971+ } catch (ReflectionException exc2) {
1972+ throw new RuntimeException(exc2.getMessage());
1973+ } catch (MBeanException exc3) {
1974+ throw new
1975+ RuntimeException((exc3.getTargetException()).getMessage());
1976+ }
1977+ }
1978+
1979+ RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoles");
1980+ return result;
1981+ }
1982+
1983+ /**
1984+ * Returns all roles present in the relation.
1985+ *
1986+ * @param relationId relation id
1987+ *
1988+ * @return a RoleResult object, including a RoleList (for roles
1989+ * successfully retrieved) and a RoleUnresolvedList (for roles not
1990+ * readable).
1991+ *
1992+ * @exception IllegalArgumentException if null parameter
1993+ * @exception RelationNotFoundException if no relation for given id
1994+ * @exception RelationServiceNotRegisteredException if the Relation
1995+ * Service is not registered in the MBean Server
1996+ */
1997+ public RoleResult getAllRoles(String relationId)
1998+ throws IllegalArgumentException,
1999+ RelationNotFoundException,
2000+ RelationServiceNotRegisteredException {
2001+
2002+ if (relationId == null) {
2003+ String excMsg = "Invalid parameter.";
2004+ throw new IllegalArgumentException(excMsg);
2005+ }
2006+
2007+ RELATION_LOGGER.entering(RelationService.class.getName(),
2008+ "getRoles", relationId);
2009+
2010+ // Can throw a RelationNotFoundException
2011+ Object relObj = getRelation(relationId);
2012+
2013+ RoleResult result;
2014+
2015+ if (relObj instanceof RelationSupport) {
2016+ // Internal relation
2017+ result = ((RelationSupport)relObj).getAllRolesInt(true, this);
2018+
2019+ } else {
2020+ // Relation MBean
2021+ // Shall not throw any Exception
2022+ try {
2023+ result = (RoleResult)
2024+ (myMBeanServer.getAttribute(((ObjectName)relObj),
2025+ "AllRoles"));
2026+ } catch (Exception exc) {
2027+ throw new RuntimeException(exc.getMessage());
2028+ }
2029+ }
2030+
2031+ RELATION_LOGGER.exiting(RelationService.class.getName(), "getRoles");
2032+ return result;
2033+ }
2034+
2035+ /**
2036+ * Retrieves the number of MBeans currently referenced in the given role.
2037+ *
2038+ * @param relationId relation id
2039+ * @param roleName name of role
2040+ *
2041+ * @return the number of currently referenced MBeans in that role
2042+ *
2043+ * @exception IllegalArgumentException if null parameter
2044+ * @exception RelationNotFoundException if no relation with given id
2045+ * @exception RoleNotFoundException if there is no role with given name
2046+ */
2047+ public Integer getRoleCardinality(String relationId,
2048+ String roleName)
2049+ throws IllegalArgumentException,
2050+ RelationNotFoundException,
2051+ RoleNotFoundException {
2052+
2053+ if (relationId == null || roleName == null) {
2054+ String excMsg = "Invalid parameter.";
2055+ throw new IllegalArgumentException(excMsg);
2056+ }
2057+
2058+ RELATION_LOGGER.entering(RelationService.class.getName(),
2059+ "getRoleCardinality", new Object[] {relationId, roleName});
2060+
2061+ // Can throw a RelationNotFoundException
2062+ Object relObj = getRelation(relationId);
2063+
2064+ Integer result;
2065+
2066+ if (relObj instanceof RelationSupport) {
2067+ // Internal relation
2068+ // Can throw RoleNotFoundException
2069+ result = ((RelationSupport)relObj).getRoleCardinality(roleName);
2070+
2071+ } else {
2072+ // Relation MBean
2073+ Object[] params = new Object[1];
2074+ params[0] = roleName;
2075+ String[] signature = new String[1];
2076+ signature[0] = "java.lang.String";
2077+ // Can throw MBeanException wrapping RoleNotFoundException:
2078+ // throw wrapped exception
2079+ //
2080+ // Shall not throw InstanceNotFoundException or ReflectionException
2081+ try {
2082+ result = (Integer)
2083+ (myMBeanServer.invoke(((ObjectName)relObj),
2084+ "getRoleCardinality",
2085+ params,
2086+ signature));
2087+ } catch (InstanceNotFoundException exc1) {
2088+ throw new RuntimeException(exc1.getMessage());
2089+ } catch (ReflectionException exc2) {
2090+ throw new RuntimeException(exc2.getMessage());
2091+ } catch (MBeanException exc3) {
2092+ Exception wrappedExc = exc3.getTargetException();
2093+ if (wrappedExc instanceof RoleNotFoundException) {
2094+ throw ((RoleNotFoundException)wrappedExc);
2095+ } else {
2096+ throw new RuntimeException(wrappedExc.getMessage());
2097+ }
2098+ }
2099+ }
2100+
2101+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2102+ "getRoleCardinality");
2103+ return result;
2104+ }
2105+
2106+ /**
2107+ * Sets the given role in given relation.
2108+ * <P>Will check the role according to its corresponding role definition
2109+ * provided in relation's relation type
2110+ * <P>The Relation Service will keep track of the change to keep the
2111+ * consistency of relations by handling referenced MBean unregistrations.
2112+ *
2113+ * @param relationId relation id
2114+ * @param role role to be set (name and new value)
2115+ *
2116+ * @exception RelationServiceNotRegisteredException if the Relation
2117+ * Service is not registered in the MBean Server
2118+ * @exception IllegalArgumentException if null parameter
2119+ * @exception RelationNotFoundException if no relation with given id
2120+ * @exception RoleNotFoundException if the role does not exist or is not
2121+ * writable
2122+ * @exception InvalidRoleValueException if value provided for role is not
2123+ * valid:
2124+ * <P>- the number of referenced MBeans in given value is less than
2125+ * expected minimum degree
2126+ * <P>or
2127+ * <P>- the number of referenced MBeans in provided value exceeds expected
2128+ * maximum degree
2129+ * <P>or
2130+ * <P>- one referenced MBean in the value is not an Object of the MBean
2131+ * class expected for that role
2132+ * <P>or
2133+ * <P>- an MBean provided for that role does not exist
2134+ *
2135+ * @see #getRole
2136+ */
2137+ public void setRole(String relationId,
2138+ Role role)
2139+ throws RelationServiceNotRegisteredException,
2140+ IllegalArgumentException,
2141+ RelationNotFoundException,
2142+ RoleNotFoundException,
2143+ InvalidRoleValueException {
2144+
2145+ if (relationId == null || role == null) {
2146+ String excMsg = "Invalid parameter.";
2147+ throw new IllegalArgumentException(excMsg);
2148+ }
2149+
2150+ RELATION_LOGGER.entering(RelationService.class.getName(),
2151+ "setRole", new Object[] {relationId, role});
2152+
2153+ // Can throw RelationServiceNotRegisteredException
2154+ isActive();
2155+
2156+ // Can throw a RelationNotFoundException
2157+ Object relObj = getRelation(relationId);
2158+
2159+ if (relObj instanceof RelationSupport) {
2160+ // Internal relation
2161+ // Can throw RoleNotFoundException,
2162+ // InvalidRoleValueException and
2163+ // RelationServiceNotRegisteredException
2164+ //
2165+ // Shall not throw RelationTypeNotFoundException
2166+ // (as relation exists in the RS, its relation type is known)
2167+ try {
2168+ ((RelationSupport)relObj).setRoleInt(role,
2169+ true,
2170+ this,
2171+ false);
2172+
2173+ } catch (RelationTypeNotFoundException exc) {
2174+ throw new RuntimeException(exc.getMessage());
2175+ }
2176+
2177+ } else {
2178+ // Relation MBean
2179+ Object[] params = new Object[1];
2180+ params[0] = role;
2181+ String[] signature = new String[1];
2182+ signature[0] = "javax.management.relation.Role";
2183+ // Can throw MBeanException wrapping RoleNotFoundException,
2184+ // InvalidRoleValueException
2185+ //
2186+ // Shall not MBeanException wrapping an MBeanException wrapping
2187+ // RelationTypeNotFoundException, or ReflectionException, or
2188+ // InstanceNotFoundException
2189+ try {
2190+ myMBeanServer.setAttribute(((ObjectName)relObj),
2191+ new Attribute("Role", role));
2192+
2193+ } catch (InstanceNotFoundException exc1) {
2194+ throw new RuntimeException(exc1.getMessage());
2195+ } catch (ReflectionException exc3) {
2196+ throw new RuntimeException(exc3.getMessage());
2197+ } catch (MBeanException exc2) {
2198+ Exception wrappedExc = exc2.getTargetException();
2199+ if (wrappedExc instanceof RoleNotFoundException) {
2200+ throw ((RoleNotFoundException)wrappedExc);
2201+ } else if (wrappedExc instanceof InvalidRoleValueException) {
2202+ throw ((InvalidRoleValueException)wrappedExc);
2203+ } else {
2204+ throw new RuntimeException(wrappedExc.getMessage());
2205+
2206+ }
2207+ } catch (AttributeNotFoundException exc4) {
2208+ throw new RuntimeException(exc4.getMessage());
2209+ } catch (InvalidAttributeValueException exc5) {
2210+ throw new RuntimeException(exc5.getMessage());
2211+ }
2212+ }
2213+
2214+ RELATION_LOGGER.exiting(RelationService.class.getName(), "setRole");
2215+ return;
2216+ }
2217+
2218+ /**
2219+ * Sets the given roles in given relation.
2220+ * <P>Will check the role according to its corresponding role definition
2221+ * provided in relation's relation type
2222+ * <P>The Relation Service keeps track of the changes to keep the
2223+ * consistency of relations by handling referenced MBean unregistrations.
2224+ *
2225+ * @param relationId relation id
2226+ * @param roleList list of roles to be set
2227+ *
2228+ * @return a RoleResult object, including a RoleList (for roles
2229+ * successfully set) and a RoleUnresolvedList (for roles not
2230+ * set).
2231+ *
2232+ * @exception RelationServiceNotRegisteredException if the Relation
2233+ * Service is not registered in the MBean Server
2234+ * @exception IllegalArgumentException if null parameter
2235+ * @exception RelationNotFoundException if no relation with given id
2236+ *
2237+ * @see #getRoles
2238+ */
2239+ public RoleResult setRoles(String relationId,
2240+ RoleList roleList)
2241+ throws RelationServiceNotRegisteredException,
2242+ IllegalArgumentException,
2243+ RelationNotFoundException {
2244+
2245+ if (relationId == null || roleList == null) {
2246+ String excMsg = "Invalid parameter.";
2247+ throw new IllegalArgumentException(excMsg);
2248+ }
2249+
2250+ RELATION_LOGGER.entering(RelationService.class.getName(),
2251+ "setRoles", new Object[] {relationId, roleList});
2252+
2253+ // Can throw RelationServiceNotRegisteredException
2254+ isActive();
2255+
2256+ // Can throw a RelationNotFoundException
2257+ Object relObj = getRelation(relationId);
2258+
2259+ RoleResult result;
2260+
2261+ if (relObj instanceof RelationSupport) {
2262+ // Internal relation
2263+ // Can throw RelationServiceNotRegisteredException
2264+ //
2265+ // Shall not throw RelationTypeNotFoundException (as relation is
2266+ // known, its relation type exists)
2267+ try {
2268+ result = ((RelationSupport)relObj).setRolesInt(roleList,
2269+ true,
2270+ this);
2271+ } catch (RelationTypeNotFoundException exc) {
2272+ throw new RuntimeException(exc.getMessage());
2273+ }
2274+
2275+ } else {
2276+ // Relation MBean
2277+ Object[] params = new Object[1];
2278+ params[0] = roleList;
2279+ String[] signature = new String[1];
2280+ signature[0] = "javax.management.relation.RoleList";
2281+ // Shall not throw InstanceNotFoundException or an MBeanException
2282+ // or ReflectionException
2283+ try {
2284+ result = (RoleResult)
2285+ (myMBeanServer.invoke(((ObjectName)relObj),
2286+ "setRoles",
2287+ params,
2288+ signature));
2289+ } catch (InstanceNotFoundException exc1) {
2290+ throw new RuntimeException(exc1.getMessage());
2291+ } catch (ReflectionException exc3) {
2292+ throw new RuntimeException(exc3.getMessage());
2293+ } catch (MBeanException exc2) {
2294+ throw new
2295+ RuntimeException((exc2.getTargetException()).getMessage());
2296+ }
2297+ }
2298+
2299+ RELATION_LOGGER.exiting(RelationService.class.getName(), "setRoles");
2300+ return result;
2301+ }
2302+
2303+ /**
2304+ * Retrieves MBeans referenced in the various roles of the relation.
2305+ *
2306+ * @param relationId relation id
2307+ *
2308+ * @return a HashMap mapping:
2309+ * <P> ObjectName -> ArrayList of String (role
2310+ * names)
2311+ *
2312+ * @exception IllegalArgumentException if null parameter
2313+ * @exception RelationNotFoundException if no relation for given
2314+ * relation id
2315+ */
2316+ public Map<ObjectName,List<String>>
2317+ getReferencedMBeans(String relationId)
2318+ throws IllegalArgumentException,
2319+ RelationNotFoundException {
2320+
2321+ if (relationId == null) {
2322+ String excMsg = "Invalid parameter.";
2323+ throw new IllegalArgumentException(excMsg);
2324+ }
2325+
2326+ RELATION_LOGGER.entering(RelationService.class.getName(),
2327+ "getReferencedMBeans", relationId);
2328+
2329+ // Can throw a RelationNotFoundException
2330+ Object relObj = getRelation(relationId);
2331+
2332+ Map<ObjectName,List<String>> result;
2333+
2334+ if (relObj instanceof RelationSupport) {
2335+ // Internal relation
2336+ result = ((RelationSupport)relObj).getReferencedMBeans();
2337+
2338+ } else {
2339+ // Relation MBean
2340+ // No Exception
2341+ try {
2342+ result = cast(
2343+ myMBeanServer.getAttribute(((ObjectName)relObj),
2344+ "ReferencedMBeans"));
2345+ } catch (Exception exc) {
2346+ throw new RuntimeException(exc.getMessage());
2347+ }
2348+ }
2349+
2350+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2351+ "getReferencedMBeans");
2352+ return result;
2353+ }
2354+
2355+ /**
2356+ * Returns name of associated relation type for given relation.
2357+ *
2358+ * @param relationId relation id
2359+ *
2360+ * @return the name of the associated relation type.
2361+ *
2362+ * @exception IllegalArgumentException if null parameter
2363+ * @exception RelationNotFoundException if no relation for given
2364+ * relation id
2365+ */
2366+ public String getRelationTypeName(String relationId)
2367+ throws IllegalArgumentException,
2368+ RelationNotFoundException {
2369+
2370+ if (relationId == null) {
2371+ String excMsg = "Invalid parameter.";
2372+ throw new IllegalArgumentException(excMsg);
2373+ }
2374+
2375+ RELATION_LOGGER.entering(RelationService.class.getName(),
2376+ "getRelationTypeName", relationId);
2377+
2378+ // Can throw a RelationNotFoundException
2379+ Object relObj = getRelation(relationId);
2380+
2381+ String result;
2382+
2383+ if (relObj instanceof RelationSupport) {
2384+ // Internal relation
2385+ result = ((RelationSupport)relObj).getRelationTypeName();
2386+
2387+ } else {
2388+ // Relation MBean
2389+ // No Exception
2390+ try {
2391+ result = (String)
2392+ (myMBeanServer.getAttribute(((ObjectName)relObj),
2393+ "RelationTypeName"));
2394+ } catch (Exception exc) {
2395+ throw new RuntimeException(exc.getMessage());
2396+ }
2397+ }
2398+
2399+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2400+ "getRelationTypeName");
2401+ return result;
2402+ }
2403+
2404+ //
2405+ // NotificationListener Interface
2406+ //
2407+
2408+ /**
2409+ * Invoked when a JMX notification occurs.
2410+ * Currently handles notifications for unregistration of MBeans, either
2411+ * referenced in a relation role or being a relation itself.
2412+ *
2413+ * @param notif The notification.
2414+ * @param handback An opaque object which helps the listener to
2415+ * associate information regarding the MBean emitter (can be null).
2416+ */
2417+ public void handleNotification(Notification notif,
2418+ Object handback) {
2419+
2420+ if (notif == null) {
2421+ String excMsg = "Invalid parameter.";
2422+ throw new IllegalArgumentException(excMsg);
2423+ }
2424+
2425+ RELATION_LOGGER.entering(RelationService.class.getName(),
2426+ "handleNotification", notif);
2427+
2428+ if (notif instanceof MBeanServerNotification) {
2429+
2430+ MBeanServerNotification mbsNtf = (MBeanServerNotification) notif;
2431+ String ntfType = notif.getType();
2432+
2433+ if (ntfType.equals(
2434+ MBeanServerNotification.UNREGISTRATION_NOTIFICATION )) {
2435+ ObjectName mbeanName =
2436+ ((MBeanServerNotification)notif).getMBeanName();
2437+
2438+ // Note: use a flag to block access to
2439+ // myRefedMBeanObjName2RelIdsMap only for a quick access
2440+ boolean isRefedMBeanFlag = false;
2441+ synchronized(myRefedMBeanObjName2RelIdsMap) {
2442+
2443+ if (myRefedMBeanObjName2RelIdsMap.containsKey(mbeanName)) {
2444+ // Unregistration of a referenced MBean
2445+ synchronized(myUnregNtfList) {
2446+ myUnregNtfList.add(mbsNtf);
2447+ }
2448+ isRefedMBeanFlag = true;
2449+ }
2450+ if (isRefedMBeanFlag && myPurgeFlag) {
2451+ // Immediate purge
2452+ // Can throw RelationServiceNotRegisteredException
2453+ // but assume that will be fine :)
2454+ try {
2455+ purgeRelations();
2456+ } catch (Exception exc) {
2457+ throw new RuntimeException(exc.getMessage());
2458+ }
2459+ }
2460+ }
2461+
2462+ // Note: do both tests as a relation can be an MBean and be
2463+ // itself referenced in another relation :)
2464+ String relId;
2465+ synchronized(myRelMBeanObjName2RelIdMap){
2466+ relId = myRelMBeanObjName2RelIdMap.get(mbeanName);
2467+ }
2468+ if (relId != null) {
2469+ // Unregistration of a relation MBean
2470+ // Can throw RelationTypeNotFoundException,
2471+ // RelationServiceNotRegisteredException
2472+ //
2473+ // Shall not throw RelationTypeNotFoundException or
2474+ // InstanceNotFoundException
2475+ try {
2476+ removeRelation(relId);
2477+ } catch (Exception exc) {
2478+ throw new RuntimeException(exc.getMessage());
2479+ }
2480+ }
2481+ }
2482+ }
2483+
2484+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2485+ "handleNotification");
2486+ return;
2487+ }
2488+
2489+ //
2490+ // NotificationBroadcaster interface
2491+ //
2492+
2493+ /**
2494+ * Returns a NotificationInfo object containing the name of the Java class
2495+ * of the notification and the notification types sent.
2496+ */
2497+ public MBeanNotificationInfo[] getNotificationInfo() {
2498+
2499+ RELATION_LOGGER.entering(RelationService.class.getName(),
2500+ "getNotificationInfo");
2501+
2502+ String ntfClass = "javax.management.relation.RelationNotification";
2503+
2504+ String[] ntfTypes = new String[] {
2505+ RelationNotification.RELATION_BASIC_CREATION,
2506+ RelationNotification.RELATION_MBEAN_CREATION,
2507+ RelationNotification.RELATION_BASIC_UPDATE,
2508+ RelationNotification.RELATION_MBEAN_UPDATE,
2509+ RelationNotification.RELATION_BASIC_REMOVAL,
2510+ RelationNotification.RELATION_MBEAN_REMOVAL,
2511+ };
2512+
2513+ String ntfDesc = "Sent when a relation is created, updated or deleted.";
2514+
2515+ MBeanNotificationInfo ntfInfo =
2516+ new MBeanNotificationInfo(ntfTypes, ntfClass, ntfDesc);
2517+
2518+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2519+ "getNotificationInfo");
2520+ return new MBeanNotificationInfo[] {ntfInfo};
2521+ }
2522+
2523+ //
2524+ // Misc
2525+ //
2526+
2527+ // Adds given object as a relation type.
2528+ //
2529+ // -param relationTypeObj relation type object
2530+ //
2531+ // -exception IllegalArgumentException if null parameter
2532+ // -exception InvalidRelationTypeException if there is already a relation
2533+ // type with that name
2534+ private void addRelationTypeInt(RelationType relationTypeObj)
2535+ throws IllegalArgumentException,
2536+ InvalidRelationTypeException {
2537+
2538+ if (relationTypeObj == null) {
2539+ String excMsg = "Invalid parameter.";
2540+ throw new IllegalArgumentException(excMsg);
2541+ }
2542+
2543+ RELATION_LOGGER.entering(RelationService.class.getName(),
2544+ "addRelationTypeInt");
2545+
2546+ String relTypeName = relationTypeObj.getRelationTypeName();
2547+
2548+ // Checks that there is not already a relation type with that name
2549+ // existing in the Relation Service
2550+ try {
2551+ // Can throw a RelationTypeNotFoundException (in fact should ;)
2552+ RelationType relType = getRelationType(relTypeName);
2553+
2554+ if (relType != null) {
2555+ String excMsg = "There is already a relation type in the Relation Service with name ";
2556+ StringBuilder excMsgStrB = new StringBuilder(excMsg);
2557+ excMsgStrB.append(relTypeName);
2558+ throw new InvalidRelationTypeException(excMsgStrB.toString());
2559+ }
2560+
2561+ } catch (RelationTypeNotFoundException exc) {
2562+ // OK : The RelationType could not be found.
2563+ }
2564+
2565+ // Adds the relation type
2566+ synchronized(myRelType2ObjMap) {
2567+ myRelType2ObjMap.put(relTypeName, relationTypeObj);
2568+ }
2569+
2570+ if (relationTypeObj instanceof RelationTypeSupport) {
2571+ ((RelationTypeSupport)relationTypeObj).setRelationServiceFlag(true);
2572+ }
2573+
2574+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2575+ "addRelationTypeInt");
2576+ return;
2577+ }
2578+
2579+ // Retrieves relation type with given name
2580+ //
2581+ // -param relationTypeName expected name of a relation type created in the
2582+ // Relation Service
2583+ //
2584+ // -return RelationType object corresponding to given name
2585+ //
2586+ // -exception IllegalArgumentException if null parameter
2587+ // -exception RelationTypeNotFoundException if no relation type for that
2588+ // name created in Relation Service
2589+ //
2590+ RelationType getRelationType(String relationTypeName)
2591+ throws IllegalArgumentException,
2592+ RelationTypeNotFoundException {
2593+
2594+ if (relationTypeName == null) {
2595+ String excMsg = "Invalid parameter.";
2596+ throw new IllegalArgumentException(excMsg);
2597+ }
2598+
2599+ RELATION_LOGGER.entering(RelationService.class.getName(),
2600+ "getRelationType", relationTypeName);
2601+
2602+ // No null relation type accepted, so can use get()
2603+ RelationType relType;
2604+ synchronized(myRelType2ObjMap) {
2605+ relType = (myRelType2ObjMap.get(relationTypeName));
2606+ }
2607+
2608+ if (relType == null) {
2609+ String excMsg = "No relation type created in the Relation Service with the name ";
2610+ StringBuilder excMsgStrB = new StringBuilder(excMsg);
2611+ excMsgStrB.append(relationTypeName);
2612+ throw new RelationTypeNotFoundException(excMsgStrB.toString());
2613+ }
2614+
2615+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2616+ "getRelationType");
2617+ return relType;
2618+ }
2619+
2620+ // Retrieves relation corresponding to given relation id.
2621+ // Returns either:
2622+ // - a RelationSupport object if the relation is internal
2623+ // or
2624+ // - the ObjectName of the corresponding MBean
2625+ //
2626+ // -param relationId expected relation id
2627+ //
2628+ // -return RelationSupport object or ObjectName of relation with given id
2629+ //
2630+ // -exception IllegalArgumentException if null parameter
2631+ // -exception RelationNotFoundException if no relation for that
2632+ // relation id created in Relation Service
2633+ //
2634+ Object getRelation(String relationId)
2635+ throws IllegalArgumentException,
2636+ RelationNotFoundException {
2637+
2638+ if (relationId == null) {
2639+ String excMsg = "Invalid parameter.";
2640+ throw new IllegalArgumentException(excMsg);
2641+ }
2642+
2643+ RELATION_LOGGER.entering(RelationService.class.getName(),
2644+ "getRelation", relationId);
2645+
2646+ // No null relation accepted, so can use get()
2647+ Object rel;
2648+ synchronized(myRelId2ObjMap) {
2649+ rel = myRelId2ObjMap.get(relationId);
2650+ }
2651+
2652+ if (rel == null) {
2653+ String excMsg = "No relation associated to relation id " + relationId;
2654+ throw new RelationNotFoundException(excMsg);
2655+ }
2656+
2657+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2658+ "getRelation");
2659+ return rel;
2660+ }
2661+
2662+ // Adds a new MBean reference (reference to an ObjectName) in the
2663+ // referenced MBean map (myRefedMBeanObjName2RelIdsMap).
2664+ //
2665+ // -param objectName ObjectName of new referenced MBean
2666+ // -param relationId relation id of the relation where the MBean is
2667+ // referenced
2668+ // -param roleName name of the role where the MBean is referenced
2669+ //
2670+ // -return boolean:
2671+ // - true if the MBean was not referenced before, so really a new
2672+ // reference
2673+ // - false else
2674+ //
2675+ // -exception IllegalArgumentException if null parameter
2676+ private boolean addNewMBeanReference(ObjectName objectName,
2677+ String relationId,
2678+ String roleName)
2679+ throws IllegalArgumentException {
2680+
2681+ if (objectName == null ||
2682+ relationId == null ||
2683+ roleName == null) {
2684+ String excMsg = "Invalid parameter.";
2685+ throw new IllegalArgumentException(excMsg);
2686+ }
2687+
2688+ RELATION_LOGGER.entering(RelationService.class.getName(),
2689+ "addNewMBeanReference",
2690+ new Object[] {objectName, relationId, roleName});
2691+
2692+ boolean isNewFlag = false;
2693+
2694+ synchronized(myRefedMBeanObjName2RelIdsMap) {
2695+
2696+ // Checks if the MBean was already referenced
2697+ // No null value allowed, use get() directly
2698+ Map<String,List<String>> mbeanRefMap =
2699+ myRefedMBeanObjName2RelIdsMap.get(objectName);
2700+
2701+ if (mbeanRefMap == null) {
2702+ // MBean not referenced in any relation yet
2703+
2704+ isNewFlag = true;
2705+
2706+ // List of roles where the MBean is referenced in given
2707+ // relation
2708+ List<String> roleNames = new ArrayList<String>();
2709+ roleNames.add(roleName);
2710+
2711+ // Map of relations where the MBean is referenced
2712+ mbeanRefMap = new HashMap<String,List<String>>();
2713+ mbeanRefMap.put(relationId, roleNames);
2714+
2715+ myRefedMBeanObjName2RelIdsMap.put(objectName, mbeanRefMap);
2716+
2717+ } else {
2718+ // MBean already referenced in at least another relation
2719+ // Checks if already referenced in another role in current
2720+ // relation
2721+ List<String> roleNames = mbeanRefMap.get(relationId);
2722+
2723+ if (roleNames == null) {
2724+ // MBean not referenced in current relation
2725+
2726+ // List of roles where the MBean is referenced in given
2727+ // relation
2728+ roleNames = new ArrayList<String>();
2729+ roleNames.add(roleName);
2730+
2731+ // Adds new reference done in current relation
2732+ mbeanRefMap.put(relationId, roleNames);
2733+
2734+ } else {
2735+ // MBean already referenced in current relation in another
2736+ // role
2737+ // Adds new reference done
2738+ roleNames.add(roleName);
2739+ }
2740+ }
2741+ }
2742+
2743+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2744+ "addNewMBeanReference");
2745+ return isNewFlag;
2746+ }
2747+
2748+ // Removes an obsolete MBean reference (reference to an ObjectName) in
2749+ // the referenced MBean map (myRefedMBeanObjName2RelIdsMap).
2750+ //
2751+ // -param objectName ObjectName of MBean no longer referenced
2752+ // -param relationId relation id of the relation where the MBean was
2753+ // referenced
2754+ // -param roleName name of the role where the MBean was referenced
2755+ // -param allRolesFlag flag, if true removes reference to MBean for all
2756+ // roles in the relation, not only for the one above
2757+ //
2758+ // -return boolean:
2759+ // - true if the MBean is no longer reference in any relation
2760+ // - false else
2761+ //
2762+ // -exception IllegalArgumentException if null parameter
2763+ private boolean removeMBeanReference(ObjectName objectName,
2764+ String relationId,
2765+ String roleName,
2766+ boolean allRolesFlag)
2767+ throws IllegalArgumentException {
2768+
2769+ if (objectName == null ||
2770+ relationId == null ||
2771+ roleName == null) {
2772+ String excMsg = "Invalid parameter.";
2773+ throw new IllegalArgumentException(excMsg);
2774+ }
2775+
2776+ RELATION_LOGGER.entering(RelationService.class.getName(),
2777+ "removeMBeanReference",
2778+ new Object[] {objectName, relationId, roleName, allRolesFlag});
2779+
2780+ boolean noLongerRefFlag = false;
2781+
2782+ synchronized(myRefedMBeanObjName2RelIdsMap) {
2783+
2784+ // Retrieves the set of relations (designed via their relation ids)
2785+ // where the MBean is referenced
2786+ // Note that it is possible that the MBean has already been removed
2787+ // from the internal map: this is the case when the MBean is
2788+ // unregistered, the role is updated, then we arrive here.
2789+ Map<String,List<String>> mbeanRefMap =
2790+ (myRefedMBeanObjName2RelIdsMap.get(objectName));
2791+
2792+ if (mbeanRefMap == null) {
2793+ // The MBean is no longer referenced
2794+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2795+ "removeMBeanReference");
2796+ return true;
2797+ }
2798+
2799+ List<String> roleNames = null;
2800+ if (!allRolesFlag) {
2801+ // Now retrieves the roles of current relation where the MBean
2802+ // was referenced
2803+ roleNames = mbeanRefMap.get(relationId);
2804+
2805+ // Removes obsolete reference to role
2806+ int obsRefIdx = roleNames.indexOf(roleName);
2807+ if (obsRefIdx != -1) {
2808+ roleNames.remove(obsRefIdx);
2809+ }
2810+ }
2811+
2812+ // Checks if there is still at least one role in current relation
2813+ // where the MBean is referenced
2814+ if (roleNames.isEmpty() || allRolesFlag) {
2815+ // MBean no longer referenced in current relation: removes
2816+ // entry
2817+ mbeanRefMap.remove(relationId);
2818+ }
2819+
2820+ // Checks if the MBean is still referenced in at least on relation
2821+ if (mbeanRefMap.isEmpty()) {
2822+ // MBean no longer referenced in any relation: removes entry
2823+ myRefedMBeanObjName2RelIdsMap.remove(objectName);
2824+ noLongerRefFlag = true;
2825+ }
2826+ }
2827+
2828+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2829+ "removeMBeanReference");
2830+ return noLongerRefFlag;
2831+ }
2832+
2833+ // Updates the listener registered to the MBean Server to be informed of
2834+ // referenced MBean unregistrations
2835+ //
2836+ // -param newRefList ArrayList of ObjectNames for new references done
2837+ // to MBeans (can be null)
2838+ // -param obsoleteRefList ArrayList of ObjectNames for obsolete references
2839+ // to MBeans (can be null)
2840+ //
2841+ // -exception RelationServiceNotRegisteredException if the Relation
2842+ // Service is not registered in the MBean Server.
2843+ private void updateUnregistrationListener(List<ObjectName> newRefList,
2844+ List<ObjectName> obsoleteRefList)
2845+ throws RelationServiceNotRegisteredException {
2846+
2847+ if (newRefList != null && obsoleteRefList != null) {
2848+ if (newRefList.isEmpty() && obsoleteRefList.isEmpty()) {
2849+ // Nothing to do :)
2850+ return;
2851+ }
2852+ }
2853+
2854+ RELATION_LOGGER.entering(RelationService.class.getName(),
2855+ "updateUnregistrationListener",
2856+ new Object[] {newRefList, obsoleteRefList});
2857+
2858+ // Can throw RelationServiceNotRegisteredException
2859+ isActive();
2860+
2861+ if (newRefList != null || obsoleteRefList != null) {
2862+
2863+ boolean newListenerFlag = false;
2864+ if (myUnregNtfFilter == null) {
2865+ // Initialize it to be able to synchronise it :)
2866+ myUnregNtfFilter = new MBeanServerNotificationFilter();
2867+ newListenerFlag = true;
2868+ }
2869+
2870+ synchronized(myUnregNtfFilter) {
2871+
2872+ // Enables ObjectNames in newRefList
2873+ if (newRefList != null) {
2874+ for (ObjectName newObjName : newRefList)
2875+ myUnregNtfFilter.enableObjectName(newObjName);
2876+ }
2877+
2878+ if (obsoleteRefList != null) {
2879+ // Disables ObjectNames in obsoleteRefList
2880+ for (ObjectName obsObjName : obsoleteRefList)
2881+ myUnregNtfFilter.disableObjectName(obsObjName);
2882+ }
2883+
2884+// Under test
2885+ if (newListenerFlag) {
2886+ try {
2887+ myMBeanServer.addNotificationListener(
2888+ MBeanServerDelegate.DELEGATE_NAME,
2889+ this,
2890+ myUnregNtfFilter,
2891+ null);
2892+ } catch (InstanceNotFoundException exc) {
2893+ throw new
2894+ RelationServiceNotRegisteredException(exc.getMessage());
2895+ }
2896+ }
2897+// End test
2898+
2899+
2900+// if (!newListenerFlag) {
2901+ // The Relation Service was already registered as a
2902+ // listener:
2903+ // removes it
2904+ // Shall not throw InstanceNotFoundException (as the
2905+ // MBean Server Delegate is expected to exist) or
2906+ // ListenerNotFoundException (as it has been checked above
2907+ // that the Relation Service is registered)
2908+// try {
2909+// myMBeanServer.removeNotificationListener(
2910+// MBeanServerDelegate.DELEGATE_NAME,
2911+// this);
2912+// } catch (InstanceNotFoundException exc1) {
2913+// throw new RuntimeException(exc1.getMessage());
2914+// } catch (ListenerNotFoundException exc2) {
2915+// throw new
2916+// RelationServiceNotRegisteredException(exc2.getMessage());
2917+// }
2918+// }
2919+
2920+ // Adds Relation Service with current filter
2921+ // Can throw InstanceNotFoundException if the Relation
2922+ // Service is not registered, to be transformed into
2923+ // RelationServiceNotRegisteredException
2924+ //
2925+ // Assume that there will not be any InstanceNotFoundException
2926+ // for the MBean Server Delegate :)
2927+// try {
2928+// myMBeanServer.addNotificationListener(
2929+// MBeanServerDelegate.DELEGATE_NAME,
2930+// this,
2931+// myUnregNtfFilter,
2932+// null);
2933+// } catch (InstanceNotFoundException exc) {
2934+// throw new
2935+// RelationServiceNotRegisteredException(exc.getMessage());
2936+// }
2937+ }
2938+ }
2939+
2940+ RELATION_LOGGER.exiting(RelationService.class.getName(),
2941+ "updateUnregistrationListener");
2942+ return;
2943+ }
2944+
2945+ // Adds a relation (being either a RelationSupport object or an MBean
2946+ // referenced using its ObjectName) in the Relation Service.
2947+ // Will send a notification RelationNotification with type:
2948+ // - RelationNotification.RELATION_BASIC_CREATION for internal relation
2949+ // creation
2950+ // - RelationNotification.RELATION_MBEAN_CREATION for an MBean being added
2951+ // as a relation.
2952+ //
2953+ // -param relationBaseFlag flag true if the relation is a RelationSupport
2954+ // object, false if it is an MBean
2955+ // -param relationObj RelationSupport object (if relation is internal)
2956+ // -param relationObjName ObjectName of the MBean to be added as a relation
2957+ // (only for the relation MBean)
2958+ // -param relationId relation identifier, to uniquely identify the relation
2959+ // inside the Relation Service
2960+ // -param relationTypeName name of the relation type (has to be created
2961+ // in the Relation Service)
2962+ // -param roleList role list to initialize roles of the relation
2963+ // (can be null)
2964+ //
2965+ // -exception IllegalArgumentException if null paramater
2966+ // -exception RelationServiceNotRegisteredException if the Relation
2967+ // Service is not registered in the MBean Server
2968+ // -exception RoleNotFoundException if a value is provided for a role
2969+ // that does not exist in the relation type
2970+ // -exception InvalidRelationIdException if relation id already used
2971+ // -exception RelationTypeNotFoundException if relation type not known in
2972+ // Relation Service
2973+ // -exception InvalidRoleValueException if:
2974+ // - the same role name is used for two different roles
2975+ // - the number of referenced MBeans in given value is less than
2976+ // expected minimum degree
2977+ // - the number of referenced MBeans in provided value exceeds expected
2978+ // maximum degree
2979+ // - one referenced MBean in the value is not an Object of the MBean
2980+ // class expected for that role
2981+ // - an MBean provided for that role does not exist
2982+ private void addRelationInt(boolean relationBaseFlag,
2983+ RelationSupport relationObj,
2984+ ObjectName relationObjName,
2985+ String relationId,
2986+ String relationTypeName,
2987+ RoleList roleList)
2988+ throws IllegalArgumentException,
2989+ RelationServiceNotRegisteredException,
2990+ RoleNotFoundException,
2991+ InvalidRelationIdException,
2992+ RelationTypeNotFoundException,
2993+ InvalidRoleValueException {
2994+
2995+ if (relationId == null ||
2996+ relationTypeName == null ||
2997+ (relationBaseFlag &&
2998+ (relationObj == null ||
2999+ relationObjName != null)) ||
3000+ (!relationBaseFlag &&
3001+ (relationObjName == null ||
3002+ relationObj != null))) {
3003+ String excMsg = "Invalid parameter.";
3004+ throw new IllegalArgumentException(excMsg);
3005+ }
3006+
3007+ RELATION_LOGGER.entering(RelationService.class.getName(),
3008+ "addRelationInt", new Object[] {relationBaseFlag, relationObj,
3009+ relationObjName, relationId, relationTypeName, roleList});
3010+
3011+ // Can throw RelationServiceNotRegisteredException
3012+ isActive();
3013+
3014+ // Checks if there is already a relation with given id
3015+ try {
3016+ // Can throw a RelationNotFoundException (in fact should :)
3017+ Object rel = getRelation(relationId);
3018+
3019+ if (rel != null) {
3020+ // There is already a relation with that id
3021+ String excMsg = "There is already a relation with id ";
3022+ StringBuilder excMsgStrB = new StringBuilder(excMsg);
3023+ excMsgStrB.append(relationId);
3024+ throw new InvalidRelationIdException(excMsgStrB.toString());
3025+ }
3026+ } catch (RelationNotFoundException exc) {
3027+ // OK : The Relation could not be found.
3028+ }
3029+
3030+ // Retrieves the relation type
3031+ // Can throw RelationTypeNotFoundException
3032+ RelationType relType = getRelationType(relationTypeName);
3033+
3034+ // Checks that each provided role conforms to its role info provided in
3035+ // the relation type
3036+ // First retrieves a local list of the role infos of the relation type
3037+ // to see which roles have not been initialized
3038+ // Note: no need to test if list not null before cloning, not allowed
3039+ // to have an empty relation type.
3040+ List<RoleInfo> roleInfoList = new ArrayList<RoleInfo>(relType.getRoleInfos());
3041+
3042+ if (roleList != null) {
3043+
3044+ for (Role currRole : roleList.asList()) {
3045+ String currRoleName = currRole.getRoleName();
3046+ List<ObjectName> currRoleValue = currRole.getRoleValue();
3047+ // Retrieves corresponding role info
3048+ // Can throw a RoleInfoNotFoundException to be converted into a
3049+ // RoleNotFoundException
3050+ RoleInfo roleInfo;
3051+ try {
3052+ roleInfo = relType.getRoleInfo(currRoleName);
3053+ } catch (RoleInfoNotFoundException exc) {
3054+ throw new RoleNotFoundException(exc.getMessage());
3055+ }
3056+
3057+ // Checks that role conforms to role info,
3058+ Integer status = checkRoleInt(2,
3059+ currRoleName,
3060+ currRoleValue,
3061+ roleInfo,
3062+ false);
3063+ int pbType = status.intValue();
3064+ if (pbType != 0) {
3065+ // A problem has occurred: throws appropriate exception
3066+ // here InvalidRoleValueException
3067+ throwRoleProblemException(pbType, currRoleName);
3068+ }
3069+
3070+ // Removes role info for that list from list of role infos for
3071+ // roles to be defaulted
3072+ int roleInfoIdx = roleInfoList.indexOf(roleInfo);
3073+ // Note: no need to check if != -1, MUST be there :)
3074+ roleInfoList.remove(roleInfoIdx);
3075+ }
3076+ }
3077+
3078+ // Initializes roles not initialized by roleList
3079+ // Can throw InvalidRoleValueException
3080+ initializeMissingRoles(relationBaseFlag,
3081+ relationObj,
3082+ relationObjName,
3083+ relationId,
3084+ relationTypeName,
3085+ roleInfoList);
3086+
3087+ // Creation of relation successfull!!!!
3088+
3089+ // Updates internal maps
3090+ // Relation id to object map
3091+ synchronized(myRelId2ObjMap) {
3092+ if (relationBaseFlag) {
3093+ // Note: do not clone relation object, created by us :)
3094+ myRelId2ObjMap.put(relationId, relationObj);
3095+ } else {
3096+ myRelId2ObjMap.put(relationId, relationObjName);
3097+ }
3098+ }
3099+
3100+ // Relation id to relation type name map
3101+ synchronized(myRelId2RelTypeMap) {
3102+ myRelId2RelTypeMap.put(relationId,
3103+ relationTypeName);
3104+ }
3105+
3106+ // Relation type to relation id map
3107+ synchronized(myRelType2RelIdsMap) {
3108+ List<String> relIdList =
3109+ myRelType2RelIdsMap.get(relationTypeName);
3110+ boolean firstRelFlag = false;
3111+ if (relIdList == null) {
3112+ firstRelFlag = true;
3113+ relIdList = new ArrayList<String>();
3114+ }
3115+ relIdList.add(relationId);
3116+ if (firstRelFlag) {
3117+ myRelType2RelIdsMap.put(relationTypeName, relIdList);
3118+ }
3119+ }
3120+
3121+ // Referenced MBean to relation id map
3122+ // Only role list parameter used, as default initialization of roles
3123+ // done automatically in initializeMissingRoles() sets each
3124+ // uninitialized role to an empty value.
3125+ for (Role currRole : roleList.asList()) {
3126+ // Creates a dummy empty ArrayList of ObjectNames to be the old
3127+ // role value :)
3128+ List<ObjectName> dummyList = new ArrayList<ObjectName>();
3129+ // Will not throw a RelationNotFoundException (as the RelId2Obj map
3130+ // has been updated above) so catch it :)
3131+ try {
3132+ updateRoleMap(relationId, currRole, dummyList);
3133+
3134+ } catch (RelationNotFoundException exc) {
3135+ // OK : The Relation could not be found.
3136+ }
3137+ }
3138+
3139+ // Sends a notification for relation creation
3140+ // Will not throw RelationNotFoundException so catch it :)
3141+ try {
3142+ sendRelationCreationNotification(relationId);
3143+
3144+ } catch (RelationNotFoundException exc) {
3145+ // OK : The Relation could not be found.
3146+ }
3147+
3148+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3149+ "addRelationInt");
3150+ return;
3151+ }
3152+
3153+ // Checks that given role conforms to given role info.
3154+ //
3155+ // -param chkType type of check:
3156+ // - 1: read, just check read access
3157+ // - 2: write, check value and write access if writeChkFlag
3158+ // -param roleName role name
3159+ // -param roleValue role value
3160+ // -param roleInfo corresponding role info
3161+ // -param writeChkFlag boolean to specify a current write access and
3162+ // to check it
3163+ //
3164+ // -return Integer with value:
3165+ // - 0: ok
3166+ // - RoleStatus.NO_ROLE_WITH_NAME
3167+ // - RoleStatus.ROLE_NOT_READABLE
3168+ // - RoleStatus.ROLE_NOT_WRITABLE
3169+ // - RoleStatus.LESS_THAN_MIN_ROLE_DEGREE
3170+ // - RoleStatus.MORE_THAN_MAX_ROLE_DEGREE
3171+ // - RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS
3172+ // - RoleStatus.REF_MBEAN_NOT_REGISTERED
3173+ //
3174+ // -exception IllegalArgumentException if null parameter
3175+ private Integer checkRoleInt(int chkType,
3176+ String roleName,
3177+ List<ObjectName> roleValue,
3178+ RoleInfo roleInfo,
3179+ boolean writeChkFlag)
3180+ throws IllegalArgumentException {
3181+
3182+ if (roleName == null ||
3183+ roleInfo == null ||
3184+ (chkType == 2 && roleValue == null)) {
3185+ String excMsg = "Invalid parameter.";
3186+ throw new IllegalArgumentException(excMsg);
3187+ }
3188+
3189+ RELATION_LOGGER.entering(RelationService.class.getName(),
3190+ "checkRoleInt", new Object[] {chkType, roleName,
3191+ roleValue, roleInfo, writeChkFlag});
3192+
3193+ // Compares names
3194+ String expName = roleInfo.getName();
3195+ if (!(roleName.equals(expName))) {
3196+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3197+ "checkRoleInt");
3198+ return Integer.valueOf(RoleStatus.NO_ROLE_WITH_NAME);
3199+ }
3200+
3201+ // Checks read access if required
3202+ if (chkType == 1) {
3203+ boolean isReadable = roleInfo.isReadable();
3204+ if (!isReadable) {
3205+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3206+ "checkRoleInt");
3207+ return Integer.valueOf(RoleStatus.ROLE_NOT_READABLE);
3208+ } else {
3209+ // End of check :)
3210+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3211+ "checkRoleInt");
3212+ return new Integer(0);
3213+ }
3214+ }
3215+
3216+ // Checks write access if required
3217+ if (writeChkFlag) {
3218+ boolean isWritable = roleInfo.isWritable();
3219+ if (!isWritable) {
3220+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3221+ "checkRoleInt");
3222+ return new Integer(RoleStatus.ROLE_NOT_WRITABLE);
3223+ }
3224+ }
3225+
3226+ int refNbr = roleValue.size();
3227+
3228+ // Checks minimum cardinality
3229+ boolean chkMinFlag = roleInfo.checkMinDegree(refNbr);
3230+ if (!chkMinFlag) {
3231+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3232+ "checkRoleInt");
3233+ return new Integer(RoleStatus.LESS_THAN_MIN_ROLE_DEGREE);
3234+ }
3235+
3236+ // Checks maximum cardinality
3237+ boolean chkMaxFlag = roleInfo.checkMaxDegree(refNbr);
3238+ if (!chkMaxFlag) {
3239+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3240+ "checkRoleInt");
3241+ return new Integer(RoleStatus.MORE_THAN_MAX_ROLE_DEGREE);
3242+ }
3243+
3244+ // Verifies that each referenced MBean is registered in the MBean
3245+ // Server and that it is an instance of the class specified in the
3246+ // role info, or of a subclass of it
3247+ // Note that here again this is under the assumption that
3248+ // referenced MBeans, relation MBeans and the Relation Service are
3249+ // registered in the same MBean Server.
3250+ String expClassName = roleInfo.getRefMBeanClassName();
3251+
3252+ for (ObjectName currObjName : roleValue) {
3253+
3254+ // Checks it is registered
3255+ if (currObjName == null) {
3256+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3257+ "checkRoleInt");
3258+ return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED);
3259+ }
3260+
3261+ // Checks if it is of the correct class
3262+ // Can throw an InstanceNotFoundException, if MBean not registered
3263+ try {
3264+ boolean classSts = myMBeanServer.isInstanceOf(currObjName,
3265+ expClassName);
3266+ if (!classSts) {
3267+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3268+ "checkRoleInt");
3269+ return new Integer(RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS);
3270+ }
3271+
3272+ } catch (InstanceNotFoundException exc) {
3273+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3274+ "checkRoleInt");
3275+ return new Integer(RoleStatus.REF_MBEAN_NOT_REGISTERED);
3276+ }
3277+ }
3278+
3279+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3280+ "checkRoleInt");
3281+ return new Integer(0);
3282+ }
3283+
3284+
3285+ // Initializes roles associated to given role infos to default value (empty
3286+ // ArrayList of ObjectNames) in given relation.
3287+ // It will succeed for every role except if the role info has a minimum
3288+ // cardinality greater than 0. In that case, an InvalidRoleValueException
3289+ // will be raised.
3290+ //
3291+ // -param relationBaseFlag flag true if the relation is a RelationSupport
3292+ // object, false if it is an MBean
3293+ // -param relationObj RelationSupport object (if relation is internal)
3294+ // -param relationObjName ObjectName of the MBean to be added as a relation
3295+ // (only for the relation MBean)
3296+ // -param relationId relation id
3297+ // -param relationTypeName name of the relation type (has to be created
3298+ // in the Relation Service)
3299+ // -param roleInfoList list of role infos for roles to be defaulted
3300+ //
3301+ // -exception IllegalArgumentException if null paramater
3302+ // -exception RelationServiceNotRegisteredException if the Relation
3303+ // Service is not registered in the MBean Server
3304+ // -exception InvalidRoleValueException if role must have a non-empty
3305+ // value
3306+
3307+ // Revisit [cebro] Handle CIM qualifiers as REQUIRED to detect roles which
3308+ // should have been initialized by the user
3309+ private void initializeMissingRoles(boolean relationBaseFlag,
3310+ RelationSupport relationObj,
3311+ ObjectName relationObjName,
3312+ String relationId,
3313+ String relationTypeName,
3314+ List<RoleInfo> roleInfoList)
3315+ throws IllegalArgumentException,
3316+ RelationServiceNotRegisteredException,
3317+ InvalidRoleValueException {
3318+
3319+ if ((relationBaseFlag &&
3320+ (relationObj == null ||
3321+ relationObjName != null)) ||
3322+ (!relationBaseFlag &&
3323+ (relationObjName == null ||
3324+ relationObj != null)) ||
3325+ relationId == null ||
3326+ relationTypeName == null ||
3327+ roleInfoList == null) {
3328+ String excMsg = "Invalid parameter.";
3329+ throw new IllegalArgumentException(excMsg);
3330+ }
3331+
3332+ RELATION_LOGGER.entering(RelationService.class.getName(),
3333+ "initializeMissingRoles", new Object[] {relationBaseFlag,
3334+ relationObj, relationObjName, relationId, relationTypeName,
3335+ roleInfoList});
3336+
3337+ // Can throw RelationServiceNotRegisteredException
3338+ isActive();
3339+
3340+ // For each role info (corresponding to a role not initialized by the
3341+ // role list provided by the user), try to set in the relation a role
3342+ // with an empty list of ObjectNames.
3343+ // A check is performed to verify that the role can be set to an
3344+ // empty value, according to its minimum cardinality
3345+ for (RoleInfo currRoleInfo : roleInfoList) {
3346+
3347+ String roleName = currRoleInfo.getName();
3348+
3349+ // Creates an empty value
3350+ List<ObjectName> emptyValue = new ArrayList<ObjectName>();
3351+ // Creates a role
3352+ Role role = new Role(roleName, emptyValue);
3353+
3354+ if (relationBaseFlag) {
3355+
3356+ // Internal relation
3357+ // Can throw InvalidRoleValueException
3358+ //
3359+ // Will not throw RoleNotFoundException (role to be
3360+ // initialized), or RelationNotFoundException, or
3361+ // RelationTypeNotFoundException
3362+ try {
3363+ relationObj.setRoleInt(role, true, this, false);
3364+
3365+ } catch (RoleNotFoundException exc1) {
3366+ throw new RuntimeException(exc1.getMessage());
3367+ } catch (RelationNotFoundException exc2) {
3368+ throw new RuntimeException(exc2.getMessage());
3369+ } catch (RelationTypeNotFoundException exc3) {
3370+ throw new RuntimeException(exc3.getMessage());
3371+ }
3372+
3373+ } else {
3374+
3375+ // Relation is an MBean
3376+ // Use standard setRole()
3377+ Object[] params = new Object[1];
3378+ params[0] = role;
3379+ String[] signature = new String[1];
3380+ signature[0] = "javax.management.relation.Role";
3381+ // Can throw MBeanException wrapping
3382+ // InvalidRoleValueException. Returns the target exception to
3383+ // be homogeneous.
3384+ //
3385+ // Will not throw MBeanException (wrapping
3386+ // RoleNotFoundException or MBeanException) or
3387+ // InstanceNotFoundException, or ReflectionException
3388+ //
3389+ // Again here the assumption is that the Relation Service and
3390+ // the relation MBeans are registered in the same MBean Server.
3391+ try {
3392+ myMBeanServer.setAttribute(relationObjName,
3393+ new Attribute("Role", role));
3394+
3395+ } catch (InstanceNotFoundException exc1) {
3396+ throw new RuntimeException(exc1.getMessage());
3397+ } catch (ReflectionException exc3) {
3398+ throw new RuntimeException(exc3.getMessage());
3399+ } catch (MBeanException exc2) {
3400+ Exception wrappedExc = exc2.getTargetException();
3401+ if (wrappedExc instanceof InvalidRoleValueException) {
3402+ throw ((InvalidRoleValueException)wrappedExc);
3403+ } else {
3404+ throw new RuntimeException(wrappedExc.getMessage());
3405+ }
3406+ } catch (AttributeNotFoundException exc4) {
3407+ throw new RuntimeException(exc4.getMessage());
3408+ } catch (InvalidAttributeValueException exc5) {
3409+ throw new RuntimeException(exc5.getMessage());
3410+ }
3411+ }
3412+ }
3413+
3414+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3415+ "initializeMissingRoles");
3416+ return;
3417+ }
3418+
3419+ // Throws an exception corresponding to a given problem type
3420+ //
3421+ // -param pbType possible problem, defined in RoleUnresolved
3422+ // -param roleName role name
3423+ //
3424+ // -exception IllegalArgumentException if null parameter
3425+ // -exception RoleNotFoundException for problems:
3426+ // - NO_ROLE_WITH_NAME
3427+ // - ROLE_NOT_READABLE
3428+ // - ROLE_NOT_WRITABLE
3429+ // -exception InvalidRoleValueException for problems:
3430+ // - LESS_THAN_MIN_ROLE_DEGREE
3431+ // - MORE_THAN_MAX_ROLE_DEGREE
3432+ // - REF_MBEAN_OF_INCORRECT_CLASS
3433+ // - REF_MBEAN_NOT_REGISTERED
3434+ static void throwRoleProblemException(int pbType,
3435+ String roleName)
3436+ throws IllegalArgumentException,
3437+ RoleNotFoundException,
3438+ InvalidRoleValueException {
3439+
3440+ if (roleName == null) {
3441+ String excMsg = "Invalid parameter.";
3442+ throw new IllegalArgumentException(excMsg);
3443+ }
3444+
3445+ // Exception type: 1 = RoleNotFoundException
3446+ // 2 = InvalidRoleValueException
3447+ int excType = 0;
3448+
3449+ String excMsgPart = null;
3450+
3451+ switch (pbType) {
3452+ case RoleStatus.NO_ROLE_WITH_NAME:
3453+ excMsgPart = " does not exist in relation.";
3454+ excType = 1;
3455+ break;
3456+ case RoleStatus.ROLE_NOT_READABLE:
3457+ excMsgPart = " is not readable.";
3458+ excType = 1;
3459+ break;
3460+ case RoleStatus.ROLE_NOT_WRITABLE:
3461+ excMsgPart = " is not writable.";
3462+ excType = 1;
3463+ break;
3464+ case RoleStatus.LESS_THAN_MIN_ROLE_DEGREE:
3465+ excMsgPart = " has a number of MBean references less than the expected minimum degree.";
3466+ excType = 2;
3467+ break;
3468+ case RoleStatus.MORE_THAN_MAX_ROLE_DEGREE:
3469+ excMsgPart = " has a number of MBean references greater than the expected maximum degree.";
3470+ excType = 2;
3471+ break;
3472+ case RoleStatus.REF_MBEAN_OF_INCORRECT_CLASS:
3473+ excMsgPart = " has an MBean reference to an MBean not of the expected class of references for that role.";
3474+ excType = 2;
3475+ break;
3476+ case RoleStatus.REF_MBEAN_NOT_REGISTERED:
3477+ excMsgPart = " has a reference to null or to an MBean not registered.";
3478+ excType = 2;
3479+ break;
3480+ }
3481+ // No default as we must have been in one of those cases
3482+
3483+ StringBuilder excMsgStrB = new StringBuilder(roleName);
3484+ excMsgStrB.append(excMsgPart);
3485+ String excMsg = excMsgStrB.toString();
3486+ if (excType == 1) {
3487+ throw new RoleNotFoundException(excMsg);
3488+
3489+ } else if (excType == 2) {
3490+ throw new InvalidRoleValueException(excMsg);
3491+ }
3492+ }
3493+
3494+ // Sends a notification of given type, with given parameters
3495+ //
3496+ // -param intNtfType integer to represent notification type:
3497+ // - 1 : create
3498+ // - 2 : update
3499+ // - 3 : delete
3500+ // -param message human-readable message
3501+ // -param relationId relation id of the created/updated/deleted relation
3502+ // -param unregMBeanList list of ObjectNames of referenced MBeans
3503+ // expected to be unregistered due to relation removal (only for removal,
3504+ // due to CIM qualifiers, can be null)
3505+ // -param roleName role name
3506+ // -param roleNewValue role new value (ArrayList of ObjectNames)
3507+ // -param oldValue old role value (ArrayList of ObjectNames)
3508+ //
3509+ // -exception IllegalArgument if null parameter
3510+ // -exception RelationNotFoundException if no relation for given id
3511+ private void sendNotificationInt(int intNtfType,
3512+ String message,
3513+ String relationId,
3514+ List<ObjectName> unregMBeanList,
3515+ String roleName,
3516+ List<ObjectName> roleNewValue,
3517+ List<ObjectName> oldValue)
3518+ throws IllegalArgumentException,
3519+ RelationNotFoundException {
3520+
3521+ if (message == null ||
3522+ relationId == null ||
3523+ (intNtfType != 3 && unregMBeanList != null) ||
3524+ (intNtfType == 2 &&
3525+ (roleName == null ||
3526+ roleNewValue == null ||
3527+ oldValue == null))) {
3528+ String excMsg = "Invalid parameter.";
3529+ throw new IllegalArgumentException(excMsg);
3530+ }
3531+
3532+ RELATION_LOGGER.entering(RelationService.class.getName(),
3533+ "sendNotificationInt", new Object[] {intNtfType, message,
3534+ relationId, unregMBeanList, roleName, roleNewValue, oldValue});
3535+
3536+ // Relation type name
3537+ // Note: do not use getRelationTypeName() as if it is a relation MBean
3538+ // it is already unregistered.
3539+ String relTypeName;
3540+ synchronized(myRelId2RelTypeMap) {
3541+ relTypeName = (myRelId2RelTypeMap.get(relationId));
3542+ }
3543+
3544+ // ObjectName (for a relation MBean)
3545+ // Can also throw a RelationNotFoundException, but detected above
3546+ ObjectName relObjName = isRelationMBean(relationId);
3547+
3548+ String ntfType = null;
3549+ if (relObjName != null) {
3550+ switch (intNtfType) {
3551+ case 1:
3552+ ntfType = RelationNotification.RELATION_MBEAN_CREATION;
3553+ break;
3554+ case 2:
3555+ ntfType = RelationNotification.RELATION_MBEAN_UPDATE;
3556+ break;
3557+ case 3:
3558+ ntfType = RelationNotification.RELATION_MBEAN_REMOVAL;
3559+ break;
3560+ }
3561+ } else {
3562+ switch (intNtfType) {
3563+ case 1:
3564+ ntfType = RelationNotification.RELATION_BASIC_CREATION;
3565+ break;
3566+ case 2:
3567+ ntfType = RelationNotification.RELATION_BASIC_UPDATE;
3568+ break;
3569+ case 3:
3570+ ntfType = RelationNotification.RELATION_BASIC_REMOVAL;
3571+ break;
3572+ }
3573+ }
3574+
3575+ // Sequence number
3576+ Long seqNo = atomicSeqNo.incrementAndGet();
3577+
3578+ // Timestamp
3579+ Date currDate = new Date();
3580+ long timeStamp = currDate.getTime();
3581+
3582+ RelationNotification ntf = null;
3583+
3584+ if (ntfType.equals(RelationNotification.RELATION_BASIC_CREATION) ||
3585+ ntfType.equals(RelationNotification.RELATION_MBEAN_CREATION) ||
3586+ ntfType.equals(RelationNotification.RELATION_BASIC_REMOVAL) ||
3587+ ntfType.equals(RelationNotification.RELATION_MBEAN_REMOVAL))
3588+
3589+ // Creation or removal
3590+ ntf = new RelationNotification(ntfType,
3591+ this,
3592+ seqNo.longValue(),
3593+ timeStamp,
3594+ message,
3595+ relationId,
3596+ relTypeName,
3597+ relObjName,
3598+ unregMBeanList);
3599+
3600+ else if (ntfType.equals(RelationNotification.RELATION_BASIC_UPDATE)
3601+ ||
3602+ ntfType.equals(RelationNotification.RELATION_MBEAN_UPDATE))
3603+ {
3604+ // Update
3605+ ntf = new RelationNotification(ntfType,
3606+ this,
3607+ seqNo.longValue(),
3608+ timeStamp,
3609+ message,
3610+ relationId,
3611+ relTypeName,
3612+ relObjName,
3613+ roleName,
3614+ roleNewValue,
3615+ oldValue);
3616+ }
3617+
3618+ sendNotification(ntf);
3619+
3620+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3621+ "sendNotificationInt");
3622+ return;
3623+ }
3624+
3625+ // Checks, for the unregistration of an MBean referenced in the roles given
3626+ // in parameter, if the relation has to be removed or not, regarding
3627+ // expected minimum role cardinality and current number of
3628+ // references in each role after removal of the current one.
3629+ // If the relation is kept, calls handleMBeanUnregistration() callback of
3630+ // the relation to update it.
3631+ //
3632+ // -param relationId relation id
3633+ // -param objectName ObjectName of the unregistered MBean
3634+ // -param roleNameList list of names of roles where the unregistered
3635+ // MBean is referenced.
3636+ //
3637+ // -exception IllegalArgumentException if null parameter
3638+ // -exception RelationServiceNotRegisteredException if the Relation
3639+ // Service is not registered in the MBean Server
3640+ // -exception RelationNotFoundException if unknown relation id
3641+ // -exception RoleNotFoundException if one role given as parameter does
3642+ // not exist in the relation
3643+ private void handleReferenceUnregistration(String relationId,
3644+ ObjectName objectName,
3645+ List<String> roleNameList)
3646+ throws IllegalArgumentException,
3647+ RelationServiceNotRegisteredException,
3648+ RelationNotFoundException,
3649+ RoleNotFoundException {
3650+
3651+ if (relationId == null ||
3652+ roleNameList == null ||
3653+ objectName == null) {
3654+ String excMsg = "Invalid parameter.";
3655+ throw new IllegalArgumentException(excMsg);
3656+ }
3657+
3658+ RELATION_LOGGER.entering(RelationService.class.getName(),
3659+ "handleReferenceUnregistration",
3660+ new Object[] {relationId, objectName, roleNameList});
3661+
3662+ // Can throw RelationServiceNotRegisteredException
3663+ isActive();
3664+
3665+ // Retrieves the relation type name of the relation
3666+ // Can throw RelationNotFoundException
3667+ String currRelTypeName = getRelationTypeName(relationId);
3668+
3669+ // Retrieves the relation
3670+ // Can throw RelationNotFoundException, but already detected above
3671+ Object relObj = getRelation(relationId);
3672+
3673+ // Flag to specify if the relation has to be deleted
3674+ boolean deleteRelFlag = false;
3675+
3676+ for (String currRoleName : roleNameList) {
3677+
3678+ if (deleteRelFlag) {
3679+ break;
3680+ }
3681+
3682+ // Retrieves number of MBeans currently referenced in role
3683+ // BEWARE! Do not use getRole() as role may be not readable
3684+ //
3685+ // Can throw RelationNotFoundException (but already checked),
3686+ // RoleNotFoundException
3687+ int currRoleRefNbr =
3688+ (getRoleCardinality(relationId, currRoleName)).intValue();
3689+
3690+ // Retrieves new number of element in role
3691+ int currRoleNewRefNbr = currRoleRefNbr - 1;
3692+
3693+ // Retrieves role info for that role
3694+ //
3695+ // Shall not throw RelationTypeNotFoundException or
3696+ // RoleInfoNotFoundException
3697+ RoleInfo currRoleInfo;
3698+ try {
3699+ currRoleInfo = getRoleInfo(currRelTypeName,
3700+ currRoleName);
3701+ } catch (RelationTypeNotFoundException exc1) {
3702+ throw new RuntimeException(exc1.getMessage());
3703+ } catch (RoleInfoNotFoundException exc2) {
3704+ throw new RuntimeException(exc2.getMessage());
3705+ }
3706+
3707+ // Checks with expected minimum number of elements
3708+ boolean chkMinFlag = currRoleInfo.checkMinDegree(currRoleNewRefNbr);
3709+
3710+ if (!chkMinFlag) {
3711+ // The relation has to be deleted
3712+ deleteRelFlag = true;
3713+ }
3714+ }
3715+
3716+ if (deleteRelFlag) {
3717+ // Removes the relation
3718+ removeRelation(relationId);
3719+
3720+ } else {
3721+
3722+ // Updates each role in the relation using
3723+ // handleMBeanUnregistration() callback
3724+ //
3725+ // BEWARE: this roleNameList list MUST BE A COPY of a role name
3726+ // list for a referenced MBean in a relation, NOT a
3727+ // reference to an original one part of the
3728+ // myRefedMBeanObjName2RelIdsMap!!!! Because each role
3729+ // which name is in that list will be updated (potentially
3730+ // using setRole(). So the Relation Service will update the
3731+ // myRefedMBeanObjName2RelIdsMap to refelect the new role
3732+ // value!
3733+ for (String currRoleName : roleNameList) {
3734+
3735+ if (relObj instanceof RelationSupport) {
3736+ // Internal relation
3737+ // Can throw RoleNotFoundException (but already checked)
3738+ //
3739+ // Shall not throw
3740+ // RelationTypeNotFoundException,
3741+ // InvalidRoleValueException (value was correct, removing
3742+ // one reference shall not invalidate it, else detected
3743+ // above)
3744+ try {
3745+ ((RelationSupport)relObj).handleMBeanUnregistrationInt(
3746+ objectName,
3747+ currRoleName,
3748+ true,
3749+ this);
3750+ } catch (RelationTypeNotFoundException exc3) {
3751+ throw new RuntimeException(exc3.getMessage());
3752+ } catch (InvalidRoleValueException exc4) {
3753+ throw new RuntimeException(exc4.getMessage());
3754+ }
3755+
3756+ } else {
3757+ // Relation MBean
3758+ Object[] params = new Object[2];
3759+ params[0] = objectName;
3760+ params[1] = currRoleName;
3761+ String[] signature = new String[2];
3762+ signature[0] = "javax.management.ObjectName";
3763+ signature[1] = "java.lang.String";
3764+ // Shall not throw InstanceNotFoundException, or
3765+ // MBeanException (wrapping RoleNotFoundException or
3766+ // MBeanException or InvalidRoleValueException) or
3767+ // ReflectionException
3768+ try {
3769+ myMBeanServer.invoke(((ObjectName)relObj),
3770+ "handleMBeanUnregistration",
3771+ params,
3772+ signature);
3773+ } catch (InstanceNotFoundException exc1) {
3774+ throw new RuntimeException(exc1.getMessage());
3775+ } catch (ReflectionException exc3) {
3776+ throw new RuntimeException(exc3.getMessage());
3777+ } catch (MBeanException exc2) {
3778+ Exception wrappedExc = exc2.getTargetException();
3779+ throw new RuntimeException(wrappedExc.getMessage());
3780+ }
3781+
3782+ }
3783+ }
3784+ }
3785+
3786+ RELATION_LOGGER.exiting(RelationService.class.getName(),
3787+ "handleReferenceUnregistration");
3788+ return;
3789+ }
3790+}