javax.management.openmbean.CompositeDataSupport Maven / Gradle / Ivy
The newest version!
/**
* Copyright (C) The MX4J Contributors.
* All rights reserved.
*
* This software is distributed under the terms of the MX4J License version 1.0.
* See the terms of the MX4J License in the documentation provided with this software.
*/
package javax.management.openmbean;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class CompositeDataSupport implements CompositeData, Serializable
{
private static final long serialVersionUID = 8003518976613702244L;
private SortedMap contents = new TreeMap();
private CompositeType compositeType;
private transient int m_hashcode = 0;
/**
* Constructs a CompositeDataSupport instance with the specified compositeType, whose item values are specified by itemValues[], in the same order as in itemNames[].
* As a CompositeType does not specify any order on its items, the itemNames[] parameter is used to specify the order in which the values are given in itemValues[].
* The items contained in this CompositeDataSupport instance are internally stored in a TreeMap, thus sorted in ascending lexicographic order of their names,
* for faster retrieval of individual item values.
* The constructor checks that all the constrainsts listed below for each parameter are satisfied, and throws the appropriate exception if they are not
*
* @param compositeType - the composite type of this composite data instance; must not be null.
* @param itemNames - itemNames must list, in any order, all the item names defined in compositeType;
* the order in which the names are listed, is used to match values in itemValues[]; must not be null or empty.
* @param itemValues - the values of the items, listed in the same order as their respective names in itemNames; each item value can be null,
* but if it is non-null it must be a valid value for the open type defined in compositeType for the corresponding item;
* must be of the same size as itemNames; must not be null or empty.
* @throws IllegalArgumentException if compositeType is null, or itemNames[] or itemValues[] is null or empty, or one of the elements in itemNames[] is a null or empty string,
* or itemNames[] and itemValues[] are not of the same size.
* @throws OpenDataException if itemNames[] or itemValues[]'s size differs from the number of items defined in compositeType, or one of the elements in itemNames[] does not exist
* as an item name defined in compositeType, or one of the elements in itemValues[] is not a valid value for the corresponding item as defined in compositeType
*/
public CompositeDataSupport(CompositeType compositeType, String[] itemNames, Object[] itemValues) throws OpenDataException
{
init(compositeType, itemNames, itemValues);
}
/**
* Constructs a CompositeDataSupport instance with the specified compositeType, whose items names and corresponding values are given by the mappings in the map items.
* This constructor converts the keys to a string array and the values to an object array and calls
* CompositeDataSupport(javax.management.openmbean.CompositeType, java.lang.String[], java.lang.Object[]).
*
* @param compositeType - the composite type of this composite data instance; must not be null.
* @param items - the mappings of all the item names to their values; items must contain all the item names defined in compositeType; must not be null or empty
* @throws IllegalArgumentException - if compositeType is null, or items is null or empty, or one of the keys in items is a null or empty string, or one of the values in items is null
* @throws OpenDataException - if items' size differs from the number of items defined in compositeType, or one of the keys in items does not exist as an item name defined in compositeType,
* or one of the values in items is not a valid value for the corresponding item as defined in compositeType.
* @throws ArrayStoreException - if any of the keys in items cannot be cast to a String
*/
public CompositeDataSupport(CompositeType compositeType, Map items) throws OpenDataException
{
init(compositeType, items != null ? (String[])items.keySet().toArray(new String[items.size()]) : null, items != null ? items.values().toArray() : null);
}
/**
* do all the work of the constructor so radObject can validate all invariants by calling the method
*/
private void init(CompositeType compositeType, String[] itemNames, Object[] itemValues) throws OpenDataException
{
if (compositeType == null) throw new IllegalArgumentException("Null CompositeType is not an acceptable value");
if (itemNames == null || itemNames.length == 0) throw new IllegalArgumentException("ItemNames cannot be null or empty (zero length)");
if (itemValues == null || itemValues.length == 0) throw new IllegalArgumentException("ItemValues cannot be null or empty (zero length)");
if (itemNames.length != itemValues.length) throw new IllegalArgumentException("Both the itemNames and itemValues arrays must be of equals length");
// now validate the the contents itemNames must be of the same length and contain all items present in the compositeType keys
validateTypes(compositeType, itemNames);
// check itemValues are valid values for openTypes
validateContents(compositeType, itemNames, itemValues);
// valid now assign compositeType
this.compositeType = compositeType;
// add the validated values and keys to the sortedMap
createMapData(itemNames, itemValues);
}
private void validateContents(CompositeType compositeType,
String[] itemNames,
Object[] itemValues)
throws OpenDataException
{
for (int i = 0; i < itemValues.length; i++)
{
if (itemValues[i] != null)
{
OpenType openType = compositeType.getType(itemNames[i]);
if (!(openType.isValue(itemValues[i])))
throw new OpenDataException("itemValue at index "
+ i
+ " is not a valid value for itemName "
+ itemNames[i]
+ " and itemType "
+ openType);
}
}
}
/**
* validates that the itemNames are present (in full) in the keySet of the compositeType
*/
private void validateTypes(CompositeType compositeType, String[] itemNames) throws OpenDataException
{
for (int i = 0; i < itemNames.length; i++)
{
if (itemNames[i] == null || itemNames[i].trim().equals("")) throw new IllegalArgumentException("Value of itemName at [" + i + "] is null or empty, unacceptable values");
}
Set keyTypes = compositeType.keySet();
if (itemNames.length != keyTypes.size()) throw new OpenDataException("The size of array arguments itemNames[] and itemValues[] should be equal to the number of items defined in argument compositeType");
if (!(Arrays.asList(itemNames).containsAll(keyTypes))) throw new OpenDataException("itemNames[] does not contain all names defined in the compositeType of this instance.");
}
/**
* fill the SortedMap with it's keys and values keys are the String[] itemNames and the values are the Object[] itemValues consisting of openTypes
*/
private void createMapData(String[] itemNames, Object[] itemValues)
{
for (int i = 0; i < itemNames.length; i++)
{
contents.put(itemNames[i], itemValues[i]);
}
}
/**
* @return the composite type of this composite data instance
*/
public CompositeType getCompositeType()
{
return compositeType;
}
/**
* @param key - the key for which to return the value
* @return - the value of the item whose name is key
* @throws IllegalArgumentException if key is null or an empty String
* @throws InvalidKeyException if key is not an existing item name for this CompositeData instance
*/
public Object get(String key)
{
if (key == null || key.trim().equals("")) throw new IllegalArgumentException("Null or empty key");
if (!(contents.containsKey(key.trim()))) throw new InvalidKeyException("Key with value " + key + " is not a current stored key in this instance");
return contents.get(key.trim());
}
/**
* Returns an array of the values of the items whose names are specified by keys, in the same order as keys this method simple calls get for each key
*
* @param the array of keys for which to return the corresponding values in the same order as specified in the keys
* @return the resulting array of values found
* @throws IllegalArgumentException if an element in keys is null or an empty String
* @throws InvalidKeyException if a key is not currently stored in this instances map
*/
public Object[] getAll(String[] keys)
{
/** should this throw an exception or under following conditions merely return an empty object[0] ?? */
if (keys == null || keys.length == 0) return new Object[0];
Object[] dataMapValues = new Object[keys.length];
for (int i = 0; i < keys.length; i++)
{
dataMapValues[i] = get(keys[i]);
}
return dataMapValues;
}
/**
* Returns true if and only if this CompositeData instance contains an item whose name is key. If key is a null or empty String, this method simply returns false
*
* @param key the key for which to find a value
* @return true if value found false otherwise
*/
public boolean containsKey(String key)
{
if (key == null || key.trim().equals("")) return false;
return contents.containsKey(key);
}
/**
* Returns true if and only if this CompositeData instance contains an item whose value is value
*
* @param value - the value to determine if present
* @return true if found false otherwise
*/
public boolean containsValue(Object value)
{
return contents.containsValue(value);
}
/**
* Returns an unmodifiable Collection view of the item values contained in this CompositeData instance. The returned collection's iterator will return the values in the
* ascending lexicographic order of the corresponding item names.
*
* @return unmodifiable collection of current values
*/
public Collection values()
{
return Collections.unmodifiableCollection(contents.values());
}
/**
* tests that the Object obj is equal to this compositeData instance
*
* @param obj - the Object to test if is equals
* @return true if and only if
*
* - obj is an instanceof CompositeData as tested by instanceof CompositeData
* - all of the name/value pairs in the objects map are equal to the name/value pairs of this instance
* - if the compositeTypes are equal
*
*/
public boolean equals(Object obj)
{
if (!(obj instanceof CompositeData))
return false;
CompositeData compositeData = (CompositeData)obj;
boolean result =
getCompositeType().equals(compositeData.getCompositeType());
if (result)
{
Iterator i = contents.entrySet().iterator();
while (i.hasNext() && result)
{
Map.Entry entry = (Map.Entry)i.next();
String key = (String)entry.getKey();
Object entryvalue = entry.getValue();
Object cdvalue = compositeData.get(key);
if (entryvalue == null)
{
result = (cdvalue == null);
}
else
{
result = entryvalue.equals(cdvalue);
}
}
}
return result;
}
/**
* Using the same information as in equals test to create the hashcode
* i.e) 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).
*
* @return the calculated HashCode for this Object
*/
public int hashCode()
{
if (m_hashcode == 0)
{
int result = getCompositeType().hashCode();
for (Iterator i = contents.entrySet().iterator(); i.hasNext();)
{
Map.Entry entry = (Map.Entry)i.next();
if (entry.getValue() != null) result += entry.getValue().hashCode();
}
m_hashcode = result;
}
return m_hashcode;
}
/**
* 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).
*
* @return a string representation of this CompositeDataSupport instance.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer(getClass().getName());
buffer.append("\tCompositeType = ");
buffer.append(compositeType.toString());
buffer.append("\tcontents are: ");
buffer.append(contents.toString());
return buffer.toString();
}
}