| /* |
| * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package javax.management.relation; |
| |
| import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER; |
| import static com.sun.jmx.mbeanserver.Util.cast; |
| import com.sun.jmx.mbeanserver.GetPropertyAction; |
| |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamField; |
| |
| import java.security.AccessController; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.logging.Level; |
| |
| /** |
| * A RelationTypeSupport object implements the RelationType interface. |
| * <P>It represents a relation type, providing role information for each role |
| * expected to be supported in every relation of that type. |
| * |
| * <P>A relation type includes a relation type name and a list of |
| * role infos (represented by RoleInfo objects). |
| * |
| * <P>A relation type has to be declared in the Relation Service: |
| * <P>- either using the createRelationType() method, where a RelationTypeSupport |
| * object will be created and kept in the Relation Service |
| * <P>- either using the addRelationType() method where the user has to create |
| * an object implementing the RelationType interface, and this object will be |
| * used as representing a relation type in the Relation Service. |
| * |
| * <p>The <b>serialVersionUID</b> of this class is <code>4611072955724144607L</code>. |
| * |
| * @since 1.5 |
| */ |
| @SuppressWarnings("serial") // serialVersionUID not constant |
| public class RelationTypeSupport implements RelationType { |
| |
| // Serialization compatibility stuff: |
| // Two serial forms are supported in this class. The selected form depends |
| // on system property "jmx.serial.form": |
| // - "1.0" for JMX 1.0 |
| // - any other value for JMX 1.1 and higher |
| // |
| // Serial version for old serial form |
| private static final long oldSerialVersionUID = -8179019472410837190L; |
| // |
| // Serial version for new serial form |
| private static final long newSerialVersionUID = 4611072955724144607L; |
| // |
| // Serializable fields in old serial form |
| private static final ObjectStreamField[] oldSerialPersistentFields = |
| { |
| new ObjectStreamField("myTypeName", String.class), |
| new ObjectStreamField("myRoleName2InfoMap", HashMap.class), |
| new ObjectStreamField("myIsInRelServFlg", boolean.class) |
| }; |
| // |
| // Serializable fields in new serial form |
| private static final ObjectStreamField[] newSerialPersistentFields = |
| { |
| new ObjectStreamField("typeName", String.class), |
| new ObjectStreamField("roleName2InfoMap", Map.class), |
| new ObjectStreamField("isInRelationService", boolean.class) |
| }; |
| // |
| // Actual serial version and serial form |
| private static final long serialVersionUID; |
| /** |
| * @serialField typeName String Relation type name |
| * @serialField roleName2InfoMap Map {@link Map} holding the mapping: |
| * <role name ({@link String})> -> <role info ({@link RoleInfo} object)> |
| * @serialField isInRelationService boolean Flag specifying whether the relation type has been declared in the |
| * Relation Service (so can no longer be updated) |
| */ |
| private static final ObjectStreamField[] serialPersistentFields; |
| private static boolean compat = false; |
| static { |
| try { |
| GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); |
| String form = AccessController.doPrivileged(act); |
| compat = (form != null && form.equals("1.0")); |
| } catch (Exception e) { |
| // OK : Too bad, no compat with 1.0 |
| } |
| if (compat) { |
| serialPersistentFields = oldSerialPersistentFields; |
| serialVersionUID = oldSerialVersionUID; |
| } else { |
| serialPersistentFields = newSerialPersistentFields; |
| serialVersionUID = newSerialVersionUID; |
| } |
| } |
| // |
| // END Serialization compatibility stuff |
| |
| // |
| // Private members |
| // |
| |
| /** |
| * @serial Relation type name |
| */ |
| private String typeName = null; |
| |
| /** |
| * @serial {@link Map} holding the mapping: |
| * <role name ({@link String})> -> <role info ({@link RoleInfo} object)> |
| */ |
| private Map<String,RoleInfo> roleName2InfoMap = |
| new HashMap<String,RoleInfo>(); |
| |
| /** |
| * @serial Flag specifying whether the relation type has been declared in the |
| * Relation Service (so can no longer be updated) |
| */ |
| private boolean isInRelationService = false; |
| |
| // |
| // Constructors |
| // |
| |
| /** |
| * Constructor where all role definitions are dynamically created and |
| * passed as parameter. |
| * |
| * @param relationTypeName Name of relation type |
| * @param roleInfoArray List of role definitions (RoleInfo objects) |
| * |
| * @exception IllegalArgumentException if null parameter |
| * @exception InvalidRelationTypeException if: |
| * <P>- the same name has been used for two different roles |
| * <P>- no role info provided |
| * <P>- one null role info provided |
| */ |
| public RelationTypeSupport(String relationTypeName, |
| RoleInfo[] roleInfoArray) |
| throws IllegalArgumentException, |
| InvalidRelationTypeException { |
| |
| if (relationTypeName == null || roleInfoArray == null) { |
| String excMsg = "Invalid parameter."; |
| throw new IllegalArgumentException(excMsg); |
| } |
| |
| RELATION_LOGGER.entering(RelationTypeSupport.class.getName(), |
| "RelationTypeSupport", relationTypeName); |
| |
| // Can throw InvalidRelationTypeException, ClassNotFoundException |
| // and NotCompliantMBeanException |
| initMembers(relationTypeName, roleInfoArray); |
| |
| RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(), |
| "RelationTypeSupport"); |
| return; |
| } |
| |
| /** |
| * Constructor to be used for subclasses. |
| * |
| * @param relationTypeName Name of relation type. |
| * |
| * @exception IllegalArgumentException if null parameter. |
| */ |
| protected RelationTypeSupport(String relationTypeName) |
| { |
| if (relationTypeName == null) { |
| String excMsg = "Invalid parameter."; |
| throw new IllegalArgumentException(excMsg); |
| } |
| |
| RELATION_LOGGER.entering(RelationTypeSupport.class.getName(), |
| "RelationTypeSupport", relationTypeName); |
| |
| typeName = relationTypeName; |
| |
| RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(), |
| "RelationTypeSupport"); |
| return; |
| } |
| |
| // |
| // Accessors |
| // |
| |
| /** |
| * Returns the relation type name. |
| * |
| * @return the relation type name. |
| */ |
| public String getRelationTypeName() { |
| return typeName; |
| } |
| |
| /** |
| * Returns the list of role definitions (ArrayList of RoleInfo objects). |
| */ |
| public List<RoleInfo> getRoleInfos() { |
| return new ArrayList<RoleInfo>(roleName2InfoMap.values()); |
| } |
| |
| /** |
| * Returns the role info (RoleInfo object) for the given role info name |
| * (null if not found). |
| * |
| * @param roleInfoName role info name |
| * |
| * @return RoleInfo object providing role definition |
| * does not exist |
| * |
| * @exception IllegalArgumentException if null parameter |
| * @exception RoleInfoNotFoundException if no role info with that name in |
| * relation type. |
| */ |
| public RoleInfo getRoleInfo(String roleInfoName) |
| throws IllegalArgumentException, |
| RoleInfoNotFoundException { |
| |
| if (roleInfoName == null) { |
| String excMsg = "Invalid parameter."; |
| throw new IllegalArgumentException(excMsg); |
| } |
| |
| RELATION_LOGGER.entering(RelationTypeSupport.class.getName(), |
| "getRoleInfo", roleInfoName); |
| |
| // No null RoleInfo allowed, so use get() |
| RoleInfo result = roleName2InfoMap.get(roleInfoName); |
| |
| if (result == null) { |
| StringBuilder excMsgStrB = new StringBuilder(); |
| String excMsg = "No role info for role "; |
| excMsgStrB.append(excMsg); |
| excMsgStrB.append(roleInfoName); |
| throw new RoleInfoNotFoundException(excMsgStrB.toString()); |
| } |
| |
| RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(), |
| "getRoleInfo"); |
| return result; |
| } |
| |
| // |
| // Misc |
| // |
| |
| /** |
| * Add a role info. |
| * This method of course should not be used after the creation of the |
| * relation type, because updating it would invalidate that the relations |
| * created associated to that type still conform to it. |
| * Can throw a RuntimeException if trying to update a relation type |
| * declared in the Relation Service. |
| * |
| * @param roleInfo role info to be added. |
| * |
| * @exception IllegalArgumentException if null parameter. |
| * @exception InvalidRelationTypeException if there is already a role |
| * info in current relation type with the same name. |
| */ |
| protected void addRoleInfo(RoleInfo roleInfo) |
| throws IllegalArgumentException, |
| InvalidRelationTypeException { |
| |
| if (roleInfo == null) { |
| String excMsg = "Invalid parameter."; |
| throw new IllegalArgumentException(excMsg); |
| } |
| |
| RELATION_LOGGER.entering(RelationTypeSupport.class.getName(), |
| "addRoleInfo", roleInfo); |
| |
| if (isInRelationService) { |
| // Trying to update a declared relation type |
| String excMsg = "Relation type cannot be updated as it is declared in the Relation Service."; |
| throw new RuntimeException(excMsg); |
| } |
| |
| String roleName = roleInfo.getName(); |
| |
| // Checks if the role info has already been described |
| if (roleName2InfoMap.containsKey(roleName)) { |
| StringBuilder excMsgStrB = new StringBuilder(); |
| String excMsg = "Two role infos provided for role "; |
| excMsgStrB.append(excMsg); |
| excMsgStrB.append(roleName); |
| throw new InvalidRelationTypeException(excMsgStrB.toString()); |
| } |
| |
| roleName2InfoMap.put(roleName, new RoleInfo(roleInfo)); |
| |
| RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(), |
| "addRoleInfo"); |
| return; |
| } |
| |
| // Sets the internal flag to specify that the relation type has been |
| // declared in the Relation Service |
| void setRelationServiceFlag(boolean flag) { |
| isInRelationService = flag; |
| return; |
| } |
| |
| // Initializes the members, i.e. type name and role info list. |
| // |
| // -param relationTypeName Name of relation type |
| // -param roleInfoArray List of role definitions (RoleInfo objects) |
| // |
| // -exception IllegalArgumentException if null parameter |
| // -exception InvalidRelationTypeException If: |
| // - the same name has been used for two different roles |
| // - no role info provided |
| // - one null role info provided |
| private void initMembers(String relationTypeName, |
| RoleInfo[] roleInfoArray) |
| throws IllegalArgumentException, |
| InvalidRelationTypeException { |
| |
| if (relationTypeName == null || roleInfoArray == null) { |
| String excMsg = "Invalid parameter."; |
| throw new IllegalArgumentException(excMsg); |
| } |
| |
| RELATION_LOGGER.entering(RelationTypeSupport.class.getName(), |
| "initMembers", relationTypeName); |
| |
| typeName = relationTypeName; |
| |
| // Verifies role infos before setting them |
| // Can throw InvalidRelationTypeException |
| checkRoleInfos(roleInfoArray); |
| |
| for (int i = 0; i < roleInfoArray.length; i++) { |
| RoleInfo currRoleInfo = roleInfoArray[i]; |
| roleName2InfoMap.put(currRoleInfo.getName(), |
| new RoleInfo(currRoleInfo)); |
| } |
| |
| RELATION_LOGGER.exiting(RelationTypeSupport.class.getName(), |
| "initMembers"); |
| return; |
| } |
| |
| // Checks the given RoleInfo array to verify that: |
| // - the array is not empty |
| // - it does not contain a null element |
| // - a given role name is used only for one RoleInfo |
| // |
| // -param roleInfoArray array to be checked |
| // |
| // -exception IllegalArgumentException |
| // -exception InvalidRelationTypeException If: |
| // - the same name has been used for two different roles |
| // - no role info provided |
| // - one null role info provided |
| static void checkRoleInfos(RoleInfo[] roleInfoArray) |
| throws IllegalArgumentException, |
| InvalidRelationTypeException { |
| |
| if (roleInfoArray == null) { |
| String excMsg = "Invalid parameter."; |
| throw new IllegalArgumentException(excMsg); |
| } |
| |
| if (roleInfoArray.length == 0) { |
| // No role info provided |
| String excMsg = "No role info provided."; |
| throw new InvalidRelationTypeException(excMsg); |
| } |
| |
| |
| Set<String> roleNames = new HashSet<String>(); |
| |
| for (int i = 0; i < roleInfoArray.length; i++) { |
| RoleInfo currRoleInfo = roleInfoArray[i]; |
| |
| if (currRoleInfo == null) { |
| String excMsg = "Null role info provided."; |
| throw new InvalidRelationTypeException(excMsg); |
| } |
| |
| String roleName = currRoleInfo.getName(); |
| |
| // Checks if the role info has already been described |
| if (roleNames.contains(roleName)) { |
| StringBuilder excMsgStrB = new StringBuilder(); |
| String excMsg = "Two role infos provided for role "; |
| excMsgStrB.append(excMsg); |
| excMsgStrB.append(roleName); |
| throw new InvalidRelationTypeException(excMsgStrB.toString()); |
| } |
| roleNames.add(roleName); |
| } |
| |
| return; |
| } |
| |
| |
| /** |
| * Deserializes a {@link RelationTypeSupport} from an {@link ObjectInputStream}. |
| */ |
| private void readObject(ObjectInputStream in) |
| throws IOException, ClassNotFoundException { |
| if (compat) |
| { |
| // Read an object serialized in the old serial form |
| // |
| ObjectInputStream.GetField fields = in.readFields(); |
| typeName = (String) fields.get("myTypeName", null); |
| if (fields.defaulted("myTypeName")) |
| { |
| throw new NullPointerException("myTypeName"); |
| } |
| roleName2InfoMap = cast(fields.get("myRoleName2InfoMap", null)); |
| if (fields.defaulted("myRoleName2InfoMap")) |
| { |
| throw new NullPointerException("myRoleName2InfoMap"); |
| } |
| isInRelationService = fields.get("myIsInRelServFlg", false); |
| if (fields.defaulted("myIsInRelServFlg")) |
| { |
| throw new NullPointerException("myIsInRelServFlg"); |
| } |
| } |
| else |
| { |
| // Read an object serialized in the new serial form |
| // |
| in.defaultReadObject(); |
| } |
| } |
| |
| |
| /** |
| * Serializes a {@link RelationTypeSupport} to an {@link ObjectOutputStream}. |
| */ |
| private void writeObject(ObjectOutputStream out) |
| throws IOException { |
| if (compat) |
| { |
| // Serializes this instance in the old serial form |
| // |
| ObjectOutputStream.PutField fields = out.putFields(); |
| fields.put("myTypeName", typeName); |
| fields.put("myRoleName2InfoMap", roleName2InfoMap); |
| fields.put("myIsInRelServFlg", isInRelationService); |
| out.writeFields(); |
| } |
| else |
| { |
| // Serializes this instance in the new serial form |
| // |
| out.defaultWriteObject(); |
| } |
| } |
| } |