/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package javax.management.openmbean; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectStreamField; import java.io.Serializable; import java.io.StreamCorruptedException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; /** * An implementation of CompositeData. * * @author Adrian Brock * @author Thomas Diesler. * * @version $Revision: 57200 $ */ public class CompositeDataSupport implements CompositeData, Serializable { // Constants ----------------------------------------------------------------- private static final long serialVersionUID = 8003518976613702244L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[] { new ObjectStreamField("contents", SortedMap.class), new ObjectStreamField("compositeType", CompositeType.class), }; // Attributes ---------------------------------------------------- /** * The contents of the composite data */ private SortedMap contents; /** * The composite type of the composite data */ private CompositeType compositeType; // cache the hashCode private int hashCode; // Static -------------------------------------------------------- // Constructors -------------------------------------------------- /** * Construct Composite Data * * @param compositeType the composite type of the data * @param itemNames the names of the values * @param itemValues the values * @exception IllegalArgumentException for a null or empty argument * @exception OpenDataException when the items do not match the * CompositeType */ public CompositeDataSupport(CompositeType compositeType, String[] itemNames, Object[] itemValues) throws OpenDataException { if (compositeType == null) throw new IllegalArgumentException("null compositeType"); if (itemNames == null) throw new IllegalArgumentException("null itemNames"); if (itemValues == null) throw new IllegalArgumentException("null itemValues"); if (itemNames.length == 0) throw new IllegalArgumentException("empty itemNames"); if (itemValues.length == 0) throw new IllegalArgumentException("empty itemValues"); if (itemNames.length != itemValues.length) throw new IllegalArgumentException("itemNames has size " + itemNames.length + " but itemValues has size " + itemValues.length); int compositeNameSize = compositeType.keySet().size(); if (itemNames.length != compositeNameSize) throw new OpenDataException("itemNames has size " + itemNames.length + " but composite type has size " + compositeNameSize); this.compositeType = compositeType; contents = new TreeMap(); for (int i = 0; i < itemNames.length; i++) { if (itemNames[i] == null || itemNames[i].length() == 0) throw new IllegalArgumentException("Item name " + i + " is null or empty"); if (contents.get(itemNames[i]) != null) throw new OpenDataException("duplicate item name " + itemNames[i]); OpenType openType = compositeType.getType(itemNames[i]); if (openType == null) throw new OpenDataException("item name not in composite type " + itemNames[i]); if (itemValues[i] != null && openType.isValue(itemValues[i]) == false) throw new OpenDataException("item value " + itemValues[i] + " for item name " + itemNames[i] + " is not a " + openType); contents.put(itemNames[i], itemValues[i]); } } /** * Construct Composite Data * * @param compositeType the composite type of the data * @param items map of strings to values * @exception IllegalArgumentException for a null or empty argument * @exception OpenDataException when the items do not match the * CompositeType * @exception ArrayStoreException when a key to the map is not a String */ public CompositeDataSupport(CompositeType compositeType, Map items) throws OpenDataException { init(compositeType, items); } // Public -------------------------------------------------------- // Composite Data Implementation --------------------------------- public CompositeType getCompositeType() { return compositeType; } public Object get(String key) { validateKey(key); return contents.get(key); } /** * Returns an array of the values of the items whose names are specified by keys, in the same order as keys. */ public Object[] getAll(String[] keys) { if (keys == null) throw new IllegalArgumentException("Null keys"); Object[] result = new Object[keys.length]; for (int i = 0; i < keys.length; i++) { validateKey(keys[i]); result[i] = contents.get(keys[i]); } return result; } public boolean containsKey(String key) { if (key == null || key.length() == 0) return false; return contents.containsKey(key); } public boolean containsValue(Object value) { return contents.containsValue(value); } public Collection values() { return Collections.unmodifiableCollection(contents.values()); } // Serializable Implementation ----------------------------------- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField getField = in.readFields(); SortedMap contents = (SortedMap) getField.get("contents", null); CompositeType compositeType = (CompositeType) getField.get("compositeType", null); try { init(compositeType, contents); } catch (Exception e) { throw new StreamCorruptedException(e.toString()); } } // Object Overrides ---------------------------------------------- public boolean equals(Object obj) { if (obj == null || (obj instanceof CompositeData) == false) return false; if (obj == this) return true; CompositeData other = (CompositeData) obj; if (compositeType.equals(other.getCompositeType()) == false) return false; if (values().size() != other.values().size()) return false; for (Iterator i = contents.keySet().iterator(); i.hasNext();) { String key = (String) i.next(); Object thisValue = this.get(key); Object otherValue = other.get(key); if ((thisValue == null && otherValue == null || thisValue != null && thisValue.equals(otherValue)) == false) return false; } return true; } /** * Returns the hash code value for this CompositeDataSupport instance. * * The hash code of a CompositeDataSupport instance is the sum of the hash codes of all elements of information used * in equals comparisons (ie: its composite type and all the item values). * * This ensures that t1.equals(t2) implies that t1.hashCode()==t2.hashCode() for any two CompositeDataSupport * instances t1 and t2, as required by the general contract of the method Object.hashCode . * * However, note that another instance of a class implementing the CompositeData interface may be equal to this * CompositeDataSupport instance as defined by equals(java.lang.Object), but may have a different hash code if it * is calculated differently. */ public int hashCode() { if (hashCode != 0) return hashCode; hashCode = compositeType.hashCode(); Iterator it = contents.values().iterator(); while (it.hasNext()) { Object value = it.next(); if (value != null) hashCode += value.hashCode(); } return hashCode; } /** * Returns a string representation of this CompositeDataSupport instance. * * The string representation consists of the name of this class (ie javax.management.openmbean.CompositeDataSupport), * the string representation of the composite type of this instance, and the string representation of the contents * (ie list the itemName=itemValue mappings). */ public String toString() { StringBuffer buffer = new StringBuffer(getClass().getName()); buffer.append(": compositeType=["); buffer.append(getCompositeType()); buffer.append("] mappings=["); Iterator keys = compositeType.keySet().iterator(); while(keys.hasNext()) { Object key = keys.next(); buffer.append(key + "=" + contents.get(key)); if (keys.hasNext()) buffer.append(","); } buffer.append("]"); return buffer.toString(); } // Private ------------------------------------------------------- /** * Initialise the composite data * * @param compositeType the composite type of the data * @param items map of strings to values * @exception IllegalArgumentException for a null or empty argument * @exception OpenDataException when the items do not match the * CompositeType * @exception ArrayStoreException when a key to the map is not a String */ private void init(CompositeType compositeType, Map items) throws OpenDataException { if (compositeType == null) throw new IllegalArgumentException("null compositeType"); if (items == null) throw new IllegalArgumentException("null items"); if (items.size() == 0) throw new IllegalArgumentException("empty items"); int compositeNameSize = compositeType.keySet().size(); if (items.size() != compositeNameSize) throw new OpenDataException("items has size " + items.size() + " but composite type has size " + compositeNameSize); this.compositeType = compositeType; contents = new TreeMap(); for (Iterator i = items.keySet().iterator(); i.hasNext();) { Object next = i.next(); if (next != null && (next instanceof String) == false) throw new ArrayStoreException("key is not a String " + next); String key = (String) next; if (key == null || key.length() == 0) throw new IllegalArgumentException("Key is null or empty"); OpenType openType = compositeType.getType(key); if (openType == null) throw new OpenDataException("item name not in composite type " + key); Object value = items.get(key); if (value != null && openType.isValue(value) == false) throw new OpenDataException("item value " + value + " for item name " + key + " is not a " + openType); contents.put(key, value); } } /** * Validates the key against the composite type * * @param key the key to check * @exception IllegalArgumentException for a null or empty key * @exception InvalidKeyException if the key not a valid item name for the composite type */ private void validateKey(String key) throws InvalidKeyException { if (key == null || key.length() == 0) throw new IllegalArgumentException("null or empty key"); if (compositeType.containsKey(key) == false) throw new InvalidKeyException("no such item name " + key + " for composite type " + compositeType); } }