All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.management.openmbean.TabularDataSupport 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.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @version $Revision: 1.10 $
 */

/**
 * The TabularDataSupport class is the open data class which implements the TabularData and the
 * Map interfaces, and which is internally based on a hash map data structure
 */
public class TabularDataSupport implements TabularData, Map, Cloneable, Serializable
{
   private static final long serialVersionUID = 5720150593236309827L;

   private Map dataMap;
   private TabularType tabularType;

   private transient String[] m_indexNames;

   /**
    * Creates an empty TabularDataSupport instance whose open-type is tabularType, and whose underlying HashMap has a default initial capacity (101) and default load factor (0.75).
    *
    * @param tabularType the TabularTypeBackUP describing this TabularData instance, cannot be null
    */
   public TabularDataSupport(TabularType tabularType)
   {
      this(tabularType, 101, 0.75f);
   }

   /**
    * Creates an empty TabularDataSupport instance whose open-type is tabularType, and whose underlying HashMap has the specified initial capacity and load factor
    *
    * @param tabularType     - the tabular type describing this instance, cannot be null;
    * @param initialCapacity - the initial capacity of the Map
    * @param loadFactor      - the load factor of the Map
    * @throws IllegalArgumentException if the initialCapacity is less than zero, the load factor is negative or the tabularType is null
    */
   public TabularDataSupport(TabularType tabularType, int initialCapacity, float loadFactor)
   {
      if (tabularType == null) throw new IllegalArgumentException("TabularTypeBackUP instance cannot be null.");
      if (initialCapacity < 0) throw new IllegalArgumentException("The initialCapacity cannot be a negative number.");
      if (loadFactor < 0) throw new IllegalArgumentException("The load factor cannot be a negative number.");

      this.tabularType = tabularType;
      this.dataMap = new HashMap(initialCapacity, loadFactor);
      initialize();
   }

   /**
    * can be called by the readObject method to initialize the deserialized instance
    */
   private void initialize()
   {
      // get the index names list from the tabular type as these will act as the unique index into each row of the TabularData instance
      List tabularIndexList = tabularType.getIndexNames();
      m_indexNames = (String[])tabularIndexList.toArray(new String[tabularIndexList.size()]);
   }

   /**
    * get the TabularType that this instance contains
    *
    * @return TabularType describing this TabularData instance
    */
   public TabularType getTabularType()
   {
      return tabularType;
   }

   /**
    * 

Calculates the index that would be used in this TabularData instance to refer to the specified composite data value parameter is it were added * to this instance.This method checks for the type validity of the specified value, but does not check if the calculated index is already used to refer to a * value, in this tabular data instance

* * @param value - the CompositeData value whose index in this TabularData instance is to be calculated, must be of the same composite type as this instance's row type; * must not be null. * @return - the index that the specified value would have in this tabularData instance * @throws NullPointerException if value is null * @throws InvalidOpenTypeException if value does not conform to this tabular data instances' row type definition */ public Object[] calculateIndex(CompositeData value) { if (value == null) throw new NullPointerException("CompositeData object cannot be null"); if (!(value.getCompositeType().equals(tabularType.getRowType()))) throw new InvalidOpenTypeException("Invalid CompositeData object, its' tabularType is not equal to the row type of this TabularType instance"); return Collections.unmodifiableList(Arrays.asList(value.getAll(m_indexNames))).toArray(); } /** * returns true if and only if this tabularData instance contains a compositeData value (i.e. a row) whose index is the specified key. If key cannot be cast to a one dimension * array of Object instances, this method returns false, otherwise it returns the result of the call this.containsKey((Object[]) key) * * @param key - the index value * @return true if a CompositeData value is found false otherwise, false if key cannot be cast to an Object[] */ public boolean containsKey(Object key) { if (!(key instanceof Object[])) return false; return containsKey((Object[])key); } /** * Returns true if and only if this TabularData instance contains a CompositeData value (ie a row) whose index is the specified key. If key is null or does not conform to this * TabularData instance's TabularType definition, this method simply returns false. * * @param key the index value whose presence in this TabularData instance is to be tested * @return true if it is found false otherwise */ public boolean containsKey(Object[] key) { if (key == null) return false; return dataMap.containsKey(Arrays.asList(key)); } /** * Returns true if and only if this TabularData instance contains the specified CompositeData value. If value is null or does not conform to * this TabularData instance's row type definition, this method simply returns false. * * @param value - the row value whose presence in this TabularData instance is to be tested * @return true if this instance contains the specified value */ public boolean containsValue(CompositeData value) { return dataMap.containsValue(value); } /** * Returns true if and only if this TabularData instance contains the specified value. * * @param value - the row value whose presence in this TabularData instance is to be tested * @return true if this TabularData instance contains the specified row value */ public boolean containsValue(Object value) { return dataMap.containsValue(value); } /** * This method simply calls get((Object[]) key). * * @param key - the key for which to lookup the value * @return the Object found for key "key" */ public Object get(Object key) { return get((Object[])key); } /** * This method validates the key Object[] parameter. It cannot be null, or empty. It must be the same length as the indexNames of the tabularType passed into this instances * constructor, and must be a valid value i.e the value returned by the method call OpenType isValue(Object obj) must be true * * @param key - the Object[] key stored as a key in this instance * @return - the CompositeData value corresponding to the key * @throws NullPointerException if key is null or empty * @throws InvalidKeyException if an item in the array returns false for call OpenType isValue(Object o) */ public CompositeData get(Object[] key) { validateKeys(key); return (CompositeData)dataMap.get(Arrays.asList(key)); } /** * This method simply calls put((CompositeData) value) and therefore ignores its key parameter which can be null * * @return the value that is put * @throws ClassCastException if value is not an instanceof CompositeData */ public Object put(Object key, Object value) { put((CompositeData)value); return value; } /** * Adds "value" to this TabularData instance, if value's composite type is the same as this instance's row type * (ie the composite type returned by this.getTabularType().getRowType()), and if there is not already an existing value in this TabularData * instance whose index is the same as the one calculated for the value to be added. The index for value is calculated according to this TabularData instance's * TabularType definition @see javax.management.openmbean.TabularType#getIndexNames() *

* This method calls calculateIndex(CompositeData value) which validates value the returned Object[] is then converted into an unmodifiableList and stored * * @param value - the composite data value to be added as a new row to this TabularData instance; must be of the same composite type as this instance's row type; must not be null. * @throws NullPointerException if value is null * @throws InvalidOpenTypeException if value does not conform to this TabularData instance's row type definition * @throws KeyAlreadyExistsException if the underlying HashMap already contains the calculated key */ public void put(CompositeData value) { // calculateIndex method tests for null and invalid rowType List list = Collections.unmodifiableList(Arrays.asList(calculateIndex(value))); if (dataMap.containsKey(list)) throw new KeyAlreadyExistsException("The list of index names already exists in this instance"); dataMap.put(list, value); } /** * This method simply calls remove((Object[]) key). * * @param key - the Object to remove note no checks are done if key can be cast to Object[] hence if not a ClassCastException will be thrown * @throws ClassCastException if key cannot be cast to an Object[] */ public Object remove(Object key) { return remove((Object[])key); } /** * Method validates the key checking for null, zero length and if items in the key are invalid as returned by @see OpenType isValue(Object obj) * * @param key - the index of the value to get in this TabularData instance; must be valid with this TabularData instance's row type definition; must not be null. * @return previous value associated with specified key, or null if there was no mapping for key * @throws NullPointerException if key is null * @throws InvalidKeyException if the key does not conform to this TabularData instance's TabularType definition */ public CompositeData remove(Object[] key) { validateKeys(key); return (CompositeData)dataMap.remove(Arrays.asList(key)); } /** * Add all the values contained in the specified map t to this TabularData instance. This method converts the collection of values contained in this map into an * array of CompositeData values, if possible, and then calls the method putAll(CompositeData[]). Note that the keys used in the specified map t are ignored. * This method allows, for example to add the content of another TabularData instance with the same row type (but possibly different index names) into this instance. * * @param t - the map whose values are to be added as new rows to this TabularData instance; if t is null or empty, this method returns without doing anything * @throws NullPointerException - if a "value" in t is null * @throws ClassCastException - if a value in t is not an instanceof CompositeData this is a wrapper around the RuntimeException ArrayStoreException * which is generated when an attempt has been made to store the wrong type of object into an array of objects. * @throws InvalidOpenTypeException - if a value in t does not conform to this TabularData instance's row type definition * @throws KeyAlreadyExistsException - if the index for a value in t, calculated according to this TabularData instance's TabularType definition * already maps to an existing value in this instance, or two values in t have the same index. */ public void putAll(Map t) { if (t == null || t.size() == 0) return; CompositeData[] compositeData; try { compositeData = (CompositeData[])t.values().toArray(new CompositeData[t.size()]); } catch (ArrayStoreException e) { throw new ClassCastException("The values contained in t must all be of type CompositeData"); } putAll(compositeData); } /** * Adds all the elements in values to this TabularData instance. If any element in values does not satisfy the constraints defined in put, or if any two elements in values * have the same index calculated according to this TabularData instance's TabularType definition, then an exception describing the failure is thrown * and no element of values is added, thus leaving this TabularData instance unchanged. * * @param values - the array of composite data values to be added as new rows to this TabularData instance; if values is null or empty, this method returns without doing anything * @throws NullPointerException - if an element of values is null * @throws InvalidOpenTypeException - if an element of values does not conform to this TabularData instance's row type definition (ie its TabularType definition) * @throws KeyAlreadyExistsException - if the index for an element of values, calculated according to this TabularData instance's TabularType definition already * maps to an existing value in this instance, or two elements of values have the same index */ public void putAll(CompositeData[] values) { // validate values if (values == null || values.length == 0) return; /** creating a list to store all the keys obtained from method calculateIndex this is to check that no keys are duplicated */ List storeList = validateNoDuplicates(values); /** Once we have validated that there are no duplicated keys we can add them to the global map if a duplicate is found an exception is thrown leaving instance unchanged */ for (int i = 0; i < values.length; i++) { dataMap.put(storeList.get(i), values[i]); } } /** * test that the list returned from calculateIndex for each CompositeData object has no duplicates */ private List validateNoDuplicates(CompositeData[] values) { List storeList = new ArrayList(); for (int i = 0; i < values.length; i++) { List list = Collections.unmodifiableList(Arrays.asList(calculateIndex(values[i]))); /** check no duplicate keys if there is we have an invalid key */ if (storeList.contains(list)) throw new KeyAlreadyExistsException("value at [" + i + "] has the same index values as: " + storeList.indexOf(list)); /** store it to check the next values are not duplicated */ storeList.add(list); } return storeList; } /** * clears this instances internal map */ public void clear() { dataMap.clear(); } /** * @return the size of the map */ public int size() { return dataMap.size(); } /** * @return true if the map is empty false if not empty */ public boolean isEmpty() { return dataMap.isEmpty(); } /** * Returns a set view of the keys contained in the underlying map of this TabularDataSupport instance, and used to index the rows. * Each key contained in this set is an unmodifiable List. The set is backed by the underlying map of this TabularDataSupport instance, * so changes to the TabularDataSupport instance are reflected in the set, and vice-versa. The set supports element removal, which removes the * corresponding row from this TabularDataSupport instance, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. * It does not support the add or addAll operations * * @return a set view of the keys used to index the rows of this TabularDataSupport instance */ public Set keySet() { return dataMap.keySet(); } /** * Returns a collection view of the rows contained in this TabularDataSupport instance. The collection is backed by the underlying map, * so changes to the TabularDataSupport instance are reflected in the collection, and vice-versa. The collection supports element removal, * which removes the corresponding index to row mapping from this TabularDataSupport instance, via the Iterator.remove, Collection.remove, removeAll, * retainAll, and clear operations. It does not support the add or addAll operations * * @return a collection view of the values contained in this TabularDataSupport instance. */ public Collection values() { return dataMap.values(); } /** * Returns a collection view of the index to row mappings contained in this TabularDataSupport instance. Each element in the returned collection is a Map.Entry. * The collection is backed by the underlying map of this TabularDataSupport instance, in so changes to the TabularDataSupport instance are reflected the collection, and vice-versa. * The collection supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Collection.remove, removeAll, retainAll, and clear operations. * It does not support the add or addAll operations. *

NOTE Do not use the SetValue method of Map.Entry elements contained in the returned collection view. * Doing so would corrupt the index to row mappings contained in this TabularDataSupport instance

* * @return a collection view of the mappings contained in this map */ public Set entrySet() { return dataMap.entrySet(); } /** * Returns a clone of this TabularDataSupport instance: the clone is obtained by calling super.clone(), * and then cloning the underlying map. Only a shallow clone of the underlying map is made, i.e. no cloning of the indexes and row values is made as they are immutable!! * * @return a copy of the TabularDataSupport */ public Object clone() { TabularDataSupport dataSupportClone = null; try { dataSupportClone = (TabularDataSupport)super.clone(); dataSupportClone.dataMap = (HashMap)((HashMap)dataMap).clone(); } catch (CloneNotSupportedException e) { // shouldn't happen return null; } return dataSupportClone; } /** * Compares the specified obj parameter with this TabularDataSupport instance for equality * * @return true if and only if all of the following statements are true: *
    *
  • *
  • their tabular types are equal
  • *
  • *
*/ public boolean equals(Object obj) { if (!(obj instanceof TabularData)) return false; TabularData tabularData = (TabularData)obj; for (Iterator i = values().iterator(); i.hasNext();) { CompositeData compositeData = (CompositeData)i.next(); if (!(tabularData.containsValue(compositeData))) return false; } return ((getTabularType().equals(tabularData.getTabularType()) && (size() == tabularData.size()))); } /** * The hash code of a TabularDataSupport instance is the sum of the hash codes of all elements of information used in equals comparisons * (ie: its tabular type and its content, where the content is defined as all the CompositeData values). * * @return the calculated hashCode for this object */ public int hashCode() { int result = tabularType.hashCode(); for (Iterator i = values().iterator(); i.hasNext();) { result += i.next().hashCode(); } return result; } /** * The string representation consists of the name of this class (ie com.sun.jdmk.TabularDataSupport), the string representation of the tabular type of this instance, * and the string representation of the contents (ie list the key=value mappings as returned by a call to dataMap.toString()) * * @return a string representation of this TabularDataSupport instance */ public String toString() { return getClass().getName() + "(tabularType = " + tabularType.toString() + ",contains = " + dataMap.toString() + ")"; } /** * validate the Object[] of keys they cannot be null or empty. The length must be the same length as the indexNames used for the indexing rows */ private void validateKeys(Object[] key) { if (key == null || key.length == 0) throw new NullPointerException("Object[] key cannot be null or of zero length"); if (key.length != m_indexNames.length) throw new InvalidKeyException("Length of Object[] passed in as a parameter is not equal to the number of items: " + m_indexNames.length + " as specified for the indexing rows in this instance."); for (int i = 0; i < key.length; i++) { OpenType openType = tabularType.getRowType().getType(m_indexNames[i]); if ((key[i] != null) && (!(openType.isValue(key[i])))) throw new InvalidKeyException("expected value is: " + openType + " at index: " + i + " but got: " + key[i]); } } /** * acts as a second constructor so validate all invariants and recreate the object in the correct state */ private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); initialize(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy