blob: 53cf2a56a6555f4e0c01c0850c54de9609b9a9bf [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.management.relation;
27
28import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER;
29import static com.sun.jmx.mbeanserver.Util.cast;
30import com.sun.jmx.mbeanserver.GetPropertyAction;
31
32import java.io.IOException;
33import java.io.ObjectInputStream;
34import java.io.ObjectOutputStream;
35import java.io.ObjectStreamField;
36
37import java.security.AccessController;
38
39import java.util.ArrayList;
40import java.util.HashMap;
41import java.util.HashSet;
42import java.util.List;
43import java.util.Map;
44import java.util.Set;
45import java.util.logging.Level;
46
47/**
48 * A RelationTypeSupport object implements the RelationType interface.
49 * <P>It represents a relation type, providing role information for each role
50 * expected to be supported in every relation of that type.
51 *
52 * <P>A relation type includes a relation type name and a list of
53 * role infos (represented by RoleInfo objects).
54 *
55 * <P>A relation type has to be declared in the Relation Service:
56 * <P>- either using the createRelationType() method, where a RelationTypeSupport
57 * object will be created and kept in the Relation Service
58 * <P>- either using the addRelationType() method where the user has to create
59 * an object implementing the RelationType interface, and this object will be
60 * used as representing a relation type in the Relation Service.
61 *
62 * <p>The <b>serialVersionUID</b> of this class is <code>4611072955724144607L</code>.
63 *
64 * @since 1.5
65 */
66@SuppressWarnings("serial") // serialVersionUID not constant
67public class RelationTypeSupport implements RelationType {
68
69 // Serialization compatibility stuff:
70 // Two serial forms are supported in this class. The selected form depends
71 // on system property "jmx.serial.form":
72 // - "1.0" for JMX 1.0
73 // - any other value for JMX 1.1 and higher
74 //
75 // Serial version for old serial form
76 private static final long oldSerialVersionUID = -8179019472410837190L;
77 //
78 // Serial version for new serial form
79 private static final long newSerialVersionUID = 4611072955724144607L;
80 //
81 // Serializable fields in old serial form
82 private static final ObjectStreamField[] oldSerialPersistentFields =
83 {
84 new ObjectStreamField("myTypeName", String.class),
85 new ObjectStreamField("myRoleName2InfoMap", HashMap.class),
86 new ObjectStreamField("myIsInRelServFlg", boolean.class)
87 };
88 //
89 // Serializable fields in new serial form
90 private static final ObjectStreamField[] newSerialPersistentFields =
91 {
92 new ObjectStreamField("typeName", String.class),
93 new ObjectStreamField("roleName2InfoMap", Map.class),
94 new ObjectStreamField("isInRelationService", boolean.class)
95 };
96 //
97 // Actual serial version and serial form
98 private static final long serialVersionUID;
99 /**
100 * @serialField typeName String Relation type name
101 * @serialField roleName2InfoMap Map {@link Map} holding the mapping:
102 * &lt;role name ({@link String})&gt; -&gt; &lt;role info ({@link RoleInfo} object)&gt;
103 * @serialField isInRelationService boolean Flag specifying whether the relation type has been declared in the
104 * Relation Service (so can no longer be updated)
105 */
106 private static final ObjectStreamField[] serialPersistentFields;
107 private static boolean compat = false;
108 static {
109 try {
110 GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
111 String form = AccessController.doPrivileged(act);
112 compat = (form != null && form.equals("1.0"));
113 } catch (Exception e) {
114 // OK : Too bad, no compat with 1.0
115 }
116 if (compat) {
117 serialPersistentFields = oldSerialPersistentFields;
118 serialVersionUID = oldSerialVersionUID;
119 } else {
120 serialPersistentFields = newSerialPersistentFields;
121 serialVersionUID = newSerialVersionUID;
122 }
123 }
124 //
125 // END Serialization compatibility stuff
126
127 //
128 // Private members
129 //
130
131 /**
132 * @serial Relation type name
133 */
134 private String typeName = null;
135
136 /**
137 * @serial {@link Map} holding the mapping:
138 * &lt;role name ({@link String})&gt; -&gt; &lt;role info ({@link RoleInfo} object)&gt;
139 */
140 private Map<String,RoleInfo> roleName2InfoMap =
141 new HashMap<String,RoleInfo>();
142
143 /**
144 * @serial Flag specifying whether the relation type has been declared in the
145 * Relation Service (so can no longer be updated)
146 */
147 private boolean isInRelationService = false;
148
149 //
150 // Constructors
151 //
152
153 /**
154 * Constructor where all role definitions are dynamically created and
155 * passed as parameter.
156 *
157 * @param relationTypeName Name of relation type
158 * @param roleInfoArray List of role definitions (RoleInfo objects)
159 *
160 * @exception IllegalArgumentException if null parameter
161 * @exception InvalidRelationTypeException if:
162 * <P>- the same name has been used for two different roles
163 * <P>- no role info provided
164 * <P>- one null role info provided
165 */
166 public RelationTypeSupport(String relationTypeName,
167 RoleInfo[] roleInfoArray)
168 throws IllegalArgumentException,
169 InvalidRelationTypeException {
170
171 if (relationTypeName == null || roleInfoArray == null) {
172 String excMsg = "Invalid parameter.";
173 throw new IllegalArgumentException(excMsg);
174 }
175
176 RELATION_LOGGER.entering(RelationTypeSupport.class.getName(),
177 "RelationTypeSupport", relationTypeName);
178
179 // Can throw InvalidRelationTypeException, ClassNotFoundException
180 // and NotCompliantMBeanException
181 initMembers(relationTypeName, roleInfoArray);
182
183 RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(),
184 "RelationTypeSupport");
185 return;
186 }
187
188 /**
189 * Constructor to be used for subclasses.
190 *
191 * @param relationTypeName Name of relation type.
192 *
193 * @exception IllegalArgumentException if null parameter.
194 */
195 protected RelationTypeSupport(String relationTypeName)
196 {
197 if (relationTypeName == null) {
198 String excMsg = "Invalid parameter.";
199 throw new IllegalArgumentException(excMsg);
200 }
201
202 RELATION_LOGGER.entering(RelationTypeSupport.class.getName(),
203 "RelationTypeSupport", relationTypeName);
204
205 typeName = relationTypeName;
206
207 RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(),
208 "RelationTypeSupport");
209 return;
210 }
211
212 //
213 // Accessors
214 //
215
216 /**
217 * Returns the relation type name.
218 *
219 * @return the relation type name.
220 */
221 public String getRelationTypeName() {
222 return typeName;
223 }
224
225 /**
226 * Returns the list of role definitions (ArrayList of RoleInfo objects).
227 */
228 public List<RoleInfo> getRoleInfos() {
229 return new ArrayList<RoleInfo>(roleName2InfoMap.values());
230 }
231
232 /**
233 * Returns the role info (RoleInfo object) for the given role info name
234 * (null if not found).
235 *
236 * @param roleInfoName role info name
237 *
238 * @return RoleInfo object providing role definition
239 * does not exist
240 *
241 * @exception IllegalArgumentException if null parameter
242 * @exception RoleInfoNotFoundException if no role info with that name in
243 * relation type.
244 */
245 public RoleInfo getRoleInfo(String roleInfoName)
246 throws IllegalArgumentException,
247 RoleInfoNotFoundException {
248
249 if (roleInfoName == null) {
250 String excMsg = "Invalid parameter.";
251 throw new IllegalArgumentException(excMsg);
252 }
253
254 RELATION_LOGGER.entering(RelationTypeSupport.class.getName(),
255 "getRoleInfo", roleInfoName);
256
257 // No null RoleInfo allowed, so use get()
258 RoleInfo result = roleName2InfoMap.get(roleInfoName);
259
260 if (result == null) {
261 StringBuilder excMsgStrB = new StringBuilder();
262 String excMsg = "No role info for role ";
263 excMsgStrB.append(excMsg);
264 excMsgStrB.append(roleInfoName);
265 throw new RoleInfoNotFoundException(excMsgStrB.toString());
266 }
267
268 RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(),
269 "getRoleInfo");
270 return result;
271 }
272
273 //
274 // Misc
275 //
276
277 /**
278 * Add a role info.
279 * This method of course should not be used after the creation of the
280 * relation type, because updating it would invalidate that the relations
281 * created associated to that type still conform to it.
282 * Can throw a RuntimeException if trying to update a relation type
283 * declared in the Relation Service.
284 *
285 * @param roleInfo role info to be added.
286 *
287 * @exception IllegalArgumentException if null parameter.
288 * @exception InvalidRelationTypeException if there is already a role
289 * info in current relation type with the same name.
290 */
291 protected void addRoleInfo(RoleInfo roleInfo)
292 throws IllegalArgumentException,
293 InvalidRelationTypeException {
294
295 if (roleInfo == null) {
296 String excMsg = "Invalid parameter.";
297 throw new IllegalArgumentException(excMsg);
298 }
299
300 RELATION_LOGGER.entering(RelationTypeSupport.class.getName(),
301 "addRoleInfo", roleInfo);
302
303 if (isInRelationService) {
304 // Trying to update a declared relation type
305 String excMsg = "Relation type cannot be updated as it is declared in the Relation Service.";
306 throw new RuntimeException(excMsg);
307 }
308
309 String roleName = roleInfo.getName();
310
311 // Checks if the role info has already been described
312 if (roleName2InfoMap.containsKey(roleName)) {
313 StringBuilder excMsgStrB = new StringBuilder();
314 String excMsg = "Two role infos provided for role ";
315 excMsgStrB.append(excMsg);
316 excMsgStrB.append(roleName);
317 throw new InvalidRelationTypeException(excMsgStrB.toString());
318 }
319
320 roleName2InfoMap.put(roleName, new RoleInfo(roleInfo));
321
322 RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(),
323 "addRoleInfo");
324 return;
325 }
326
327 // Sets the internal flag to specify that the relation type has been
328 // declared in the Relation Service
329 void setRelationServiceFlag(boolean flag) {
330 isInRelationService = flag;
331 return;
332 }
333
334 // Initializes the members, i.e. type name and role info list.
335 //
336 // -param relationTypeName Name of relation type
337 // -param roleInfoArray List of role definitions (RoleInfo objects)
338 //
339 // -exception IllegalArgumentException if null parameter
340 // -exception InvalidRelationTypeException If:
341 // - the same name has been used for two different roles
342 // - no role info provided
343 // - one null role info provided
344 private void initMembers(String relationTypeName,
345 RoleInfo[] roleInfoArray)
346 throws IllegalArgumentException,
347 InvalidRelationTypeException {
348
349 if (relationTypeName == null || roleInfoArray == null) {
350 String excMsg = "Invalid parameter.";
351 throw new IllegalArgumentException(excMsg);
352 }
353
354 RELATION_LOGGER.entering(RelationTypeSupport.class.getName(),
355 "initMembers", relationTypeName);
356
357 typeName = relationTypeName;
358
359 // Verifies role infos before setting them
360 // Can throw InvalidRelationTypeException
361 checkRoleInfos(roleInfoArray);
362
363 for (int i = 0; i < roleInfoArray.length; i++) {
364 RoleInfo currRoleInfo = roleInfoArray[i];
365 roleName2InfoMap.put(currRoleInfo.getName(),
366 new RoleInfo(currRoleInfo));
367 }
368
369 RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(),
370 "initMembers");
371 return;
372 }
373
374 // Checks the given RoleInfo array to verify that:
375 // - the array is not empty
376 // - it does not contain a null element
377 // - a given role name is used only for one RoleInfo
378 //
379 // -param roleInfoArray array to be checked
380 //
381 // -exception IllegalArgumentException
382 // -exception InvalidRelationTypeException If:
383 // - the same name has been used for two different roles
384 // - no role info provided
385 // - one null role info provided
386 static void checkRoleInfos(RoleInfo[] roleInfoArray)
387 throws IllegalArgumentException,
388 InvalidRelationTypeException {
389
390 if (roleInfoArray == null) {
391 String excMsg = "Invalid parameter.";
392 throw new IllegalArgumentException(excMsg);
393 }
394
395 if (roleInfoArray.length == 0) {
396 // No role info provided
397 String excMsg = "No role info provided.";
398 throw new InvalidRelationTypeException(excMsg);
399 }
400
401
402 Set<String> roleNames = new HashSet<String>();
403
404 for (int i = 0; i < roleInfoArray.length; i++) {
405 RoleInfo currRoleInfo = roleInfoArray[i];
406
407 if (currRoleInfo == null) {
408 String excMsg = "Null role info provided.";
409 throw new InvalidRelationTypeException(excMsg);
410 }
411
412 String roleName = currRoleInfo.getName();
413
414 // Checks if the role info has already been described
415 if (roleNames.contains(roleName)) {
416 StringBuilder excMsgStrB = new StringBuilder();
417 String excMsg = "Two role infos provided for role ";
418 excMsgStrB.append(excMsg);
419 excMsgStrB.append(roleName);
420 throw new InvalidRelationTypeException(excMsgStrB.toString());
421 }
422 roleNames.add(roleName);
423 }
424
425 return;
426 }
427
428
429 /**
430 * Deserializes a {@link RelationTypeSupport} from an {@link ObjectInputStream}.
431 */
432 private void readObject(ObjectInputStream in)
433 throws IOException, ClassNotFoundException {
434 if (compat)
435 {
436 // Read an object serialized in the old serial form
437 //
438 ObjectInputStream.GetField fields = in.readFields();
439 typeName = (String) fields.get("myTypeName", null);
440 if (fields.defaulted("myTypeName"))
441 {
442 throw new NullPointerException("myTypeName");
443 }
444 roleName2InfoMap = cast(fields.get("myRoleName2InfoMap", null));
445 if (fields.defaulted("myRoleName2InfoMap"))
446 {
447 throw new NullPointerException("myRoleName2InfoMap");
448 }
449 isInRelationService = fields.get("myIsInRelServFlg", false);
450 if (fields.defaulted("myIsInRelServFlg"))
451 {
452 throw new NullPointerException("myIsInRelServFlg");
453 }
454 }
455 else
456 {
457 // Read an object serialized in the new serial form
458 //
459 in.defaultReadObject();
460 }
461 }
462
463
464 /**
465 * Serializes a {@link RelationTypeSupport} to an {@link ObjectOutputStream}.
466 */
467 private void writeObject(ObjectOutputStream out)
468 throws IOException {
469 if (compat)
470 {
471 // Serializes this instance in the old serial form
472 //
473 ObjectOutputStream.PutField fields = out.putFields();
474 fields.put("myTypeName", typeName);
475 fields.put("myRoleName2InfoMap", roleName2InfoMap);
476 fields.put("myIsInRelServFlg", isInRelationService);
477 out.writeFields();
478 }
479 else
480 {
481 // Serializes this instance in the new serial form
482 //
483 out.defaultWriteObject();
484 }
485 }
486}