001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.management.openmbean;
023:
024: import java.io.IOException;
025: import java.io.ObjectInputStream;
026: import java.io.ObjectStreamField;
027: import java.io.Serializable;
028: import java.io.StreamCorruptedException;
029:
030: import java.util.Arrays;
031: import java.util.Collection;
032: import java.util.HashMap;
033: import java.util.HashSet;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Map;
037: import java.util.Set;
038:
039: /**
040: * An implementation of TabularData.
041: *
042: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>
043: * @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
044: *
045: * @version $Revision: 57200 $
046: */
047: public class TabularDataSupport implements Cloneable, Map,
048: Serializable, TabularData {
049: // Constants -----------------------------------------------------------------
050:
051: private static final long serialVersionUID = 5720150593236309827L;
052: private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[] {
053: new ObjectStreamField("dataMap", Map.class),
054: new ObjectStreamField("tabularType", TabularType.class), };
055:
056: // Attributes ----------------------------------------------------
057:
058: /**
059: * The data map of this tabular data
060: */
061: private Map dataMap;
062:
063: /**
064: * The tabular type of the tabular data
065: */
066: private TabularType tabularType;
067:
068: /**
069: * The index names
070: */
071: private transient String[] indexNames;
072:
073: // Static --------------------------------------------------------
074:
075: // Constructors --------------------------------------------------
076:
077: /**
078: * Construct Tabular Data with an initial capacity of 101 and a load
079: * factor of 0.75
080: *
081: * @param tabularType the tabular type of the data
082: * @exception IllegalArgumentException for a null argument
083: */
084: public TabularDataSupport(TabularType tabularType) {
085: this (tabularType, 101, 0.75f);
086: }
087:
088: /**
089: * Construct Tabular Data
090: *
091: * @param tabularType the tabular type of the data
092: * @param initialCapacity the initial capacity of the map
093: * @param loadFactor the load factory of the map
094: * @exception IllegalArgumentException for a null argument
095: */
096: public TabularDataSupport(TabularType tabularType,
097: int initialCapacity, float loadFactor) {
098: init(new HashMap(initialCapacity, loadFactor), tabularType);
099: }
100:
101: // Public --------------------------------------------------------
102:
103: // Tabular Data Implementation -----------------------------------
104:
105: public TabularType getTabularType() {
106: return tabularType;
107: }
108:
109: public Object[] calculateIndex(CompositeData value) {
110: validateCompositeData(value);
111: return value.getAll(indexNames);
112: }
113:
114: public void clear() {
115: dataMap.clear();
116: }
117:
118: public boolean containsKey(Object[] key) {
119: if (key == null)
120: return false;
121: return dataMap.containsKey(Arrays.asList(key));
122: }
123:
124: public boolean containsValue(CompositeData value) {
125: // javadoc says check the value, but this is done at addition
126: return dataMap.containsValue(value);
127: }
128:
129: public CompositeData get(Object[] key) {
130: validateKey(key);
131: return (CompositeData) dataMap.get(Arrays.asList(key));
132: }
133:
134: public boolean isEmpty() {
135: return dataMap.isEmpty();
136: }
137:
138: public Set keySet() {
139: return dataMap.keySet();
140: }
141:
142: public void put(CompositeData value) {
143: List index = Arrays.asList(calculateIndex(value));
144: if (dataMap.containsKey(index))
145: throw new KeyAlreadyExistsException(
146: "The index is already used " + index);
147: dataMap.put(index, value);
148: }
149:
150: public void putAll(CompositeData[] values) {
151: if (values == null)
152: return;
153: HashSet keys = new HashSet();
154: for (int i = 0; i < values.length; i++) {
155: List index = Arrays.asList(calculateIndex(values[i]));
156: if (keys.contains(index))
157: throw new KeyAlreadyExistsException(
158: "Duplicate index in values " + index
159: + " for value " + values[i]);
160: keys.add(index);
161: if (dataMap.containsKey(index))
162: throw new KeyAlreadyExistsException(
163: "Index already used " + index + " for value "
164: + values[i]);
165: }
166: for (int i = 0; i < values.length; i++)
167: put(values[i]);
168: }
169:
170: public CompositeData remove(Object[] key) {
171: validateKey(key);
172: return (CompositeData) dataMap.remove(Arrays.asList(key));
173: }
174:
175: public int size() {
176: return dataMap.size();
177: }
178:
179: public Collection values() {
180: return dataMap.values();
181: }
182:
183: // Map Implementation --------------------------------------------
184:
185: public boolean containsKey(Object key) {
186: if (key == null || (key instanceof Object[]) == false)
187: return false;
188: return containsKey((Object[]) key);
189: }
190:
191: public boolean containsValue(Object value) {
192: return dataMap.containsValue(value);
193: }
194:
195: public Set entrySet() {
196: return dataMap.entrySet();
197: }
198:
199: public Object get(Object key) {
200: return get((Object[]) key);
201: }
202:
203: public Object put(Object key, Object value) {
204: put((CompositeData) value);
205: return value;
206: }
207:
208: public void putAll(Map t) {
209: if (t == null)
210: return;
211: CompositeData[] data = new CompositeData[t.size()];
212: int count = 0;
213: for (Iterator i = t.values().iterator(); i.hasNext();)
214: data[count++] = (CompositeData) i.next();
215: putAll(data);
216: }
217:
218: public Object remove(Object key) {
219: return remove((Object[]) key);
220: }
221:
222: // Cloneable Implentation ----------------------------------------
223:
224: public Object clone() {
225: try {
226: TabularDataSupport result = (TabularDataSupport) super
227: .clone();
228: result.dataMap = (Map) ((HashMap) this .dataMap).clone();
229: return result;
230: } catch (CloneNotSupportedException e) {
231: throw new RuntimeException(
232: "Unexpected clone not supported exception.");
233: }
234: }
235:
236: // Serializable Implementation -----------------------------------
237:
238: private void readObject(ObjectInputStream in) throws IOException,
239: ClassNotFoundException {
240: ObjectInputStream.GetField getField = in.readFields();
241: Map dataMap = (Map) getField.get("dataMap", null);
242: TabularType tabularType = (TabularType) getField.get(
243: "tabularType", null);
244: try {
245: init(dataMap, tabularType);
246: } catch (Exception e) {
247: throw new StreamCorruptedException(e.toString());
248: }
249: }
250:
251: // Object Overrides ----------------------------------------------
252:
253: /**
254: * Compares the specified obj parameter with this TabularDataSupport instance for equality.
255: *
256: * Returns true if and only if all of the following statements are true:
257: * - obj is non null,
258: * - obj also implements the TabularData interface,
259: * - their tabular types are equal
260: * - their contents (ie all CompositeData values) are equal.
261: *
262: * This ensures that this equals method works properly for obj parameters which are different implementations of the TabularData interface.
263: */
264: public boolean equals(Object obj) {
265: if (obj == null || (obj instanceof TabularData) == false)
266: return false;
267: if (this == obj)
268: return true;
269:
270: TabularData other = (TabularData) obj;
271: if (tabularType.equals(other.getTabularType()) == false)
272: return false;
273: if (size() != other.size())
274: return false;
275: for (Iterator i = dataMap.entrySet().iterator(); i.hasNext();) {
276: Entry entry = (Entry) i.next();
277: Object[] indexes = ((List) entry.getKey()).toArray();
278: Object this Value = entry.getValue();
279: Object otherValue = other.get(indexes);
280: if ((this Value == null && otherValue == null || this Value != null
281: && this Value.equals(otherValue)) == false)
282: return false;
283: }
284: return true;
285: }
286:
287: public int hashCode() {
288: int hash = tabularType.hashCode();
289: for (Iterator i = dataMap.values().iterator(); i.hasNext();)
290: hash += i.next().hashCode();
291: return hash;
292: }
293:
294: public String toString() {
295: StringBuffer buffer = new StringBuffer(getClass().getName());
296: buffer.append(": tabularType=[");
297: buffer.append(getTabularType());
298: buffer.append("] mappings=[");
299: Iterator entries = dataMap.entrySet().iterator();
300: while (entries.hasNext()) {
301: Entry entry = (Entry) entries.next();
302: buffer.append(entry.getKey());
303: buffer.append("=");
304: buffer.append(entry.getValue());
305: if (entries.hasNext())
306: buffer.append(",");
307: }
308: buffer.append("]");
309: return buffer.toString();
310: }
311:
312: // Private -------------------------------------------------------
313:
314: /**
315: * Initialise the tabular data
316: *
317: * @param dataMap the data
318: * @param tabularType the tabular type of the data
319: * @exception IllegalArgumentException for a null
320: */
321: private void init(Map dataMap, TabularType tabularType) {
322: if (dataMap == null)
323: throw new IllegalArgumentException("null dataMap");
324: if (tabularType == null)
325: throw new IllegalArgumentException("null tabularType");
326:
327: this .dataMap = dataMap;
328: this .tabularType = tabularType;
329: List indexNameList = tabularType.getIndexNames();
330: this .indexNames = (String[]) indexNameList
331: .toArray(new String[indexNameList.size()]);
332: }
333:
334: /**
335: * Validate the composite type against the row type
336: *
337: * @param value the composite data
338: * @exception NullPointerException for a null value
339: * @exception InvalidOpenTypeException if the value is not valid for the
340: * tabular data's row type
341: */
342: private void validateCompositeData(CompositeData value) {
343: if (value == null)
344: throw new NullPointerException("null value");
345: if (value.getCompositeType().equals(tabularType.getRowType()) == false)
346: throw new InvalidOpenTypeException(
347: "value has composite type "
348: + value.getCompositeType()
349: + " expected row type "
350: + tabularType.getRowType());
351: }
352:
353: /**
354: * Validate the key against the row type
355: *
356: * @param key the key to check
357: * @exception NullPointerException for a null key
358: * @exception InvalidKeyException if the key is not valid for the
359: * tabular data's row type
360: */
361: private void validateKey(Object[] key) {
362: if (key == null || key.length == 0)
363: throw new NullPointerException("null key");
364: if (key.length != indexNames.length)
365: throw new InvalidKeyException("key has " + key.length
366: + " elements, " + "should be " + indexNames.length);
367: for (int i = 0; i < key.length; i++) {
368: OpenType openType = tabularType.getRowType().getType(
369: indexNames[i]);
370: if (key[i] != null && openType.isValue(key[i]) == false)
371: throw new InvalidKeyException("key element " + i + " "
372: + key + " is not a value for " + openType);
373: }
374: }
375: }
|