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.Collection;
031: import java.util.Collections;
032: import java.util.Iterator;
033: import java.util.Map;
034: import java.util.SortedMap;
035: import java.util.TreeMap;
036:
037: /**
038: * An implementation of CompositeData.
039: *
040: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>
041: * @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
042: *
043: * @version $Revision: 57200 $
044: */
045: public class CompositeDataSupport implements CompositeData,
046: Serializable {
047: // Constants -----------------------------------------------------------------
048:
049: private static final long serialVersionUID = 8003518976613702244L;
050: private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[] {
051: new ObjectStreamField("contents", SortedMap.class),
052: new ObjectStreamField("compositeType", CompositeType.class), };
053:
054: // Attributes ----------------------------------------------------
055:
056: /**
057: * The contents of the composite data
058: */
059: private SortedMap contents;
060:
061: /**
062: * The composite type of the composite data
063: */
064: private CompositeType compositeType;
065:
066: // cache the hashCode
067: private int hashCode;
068:
069: // Static --------------------------------------------------------
070:
071: // Constructors --------------------------------------------------
072:
073: /**
074: * Construct Composite Data
075: *
076: * @param compositeType the composite type of the data
077: * @param itemNames the names of the values
078: * @param itemValues the values
079: * @exception IllegalArgumentException for a null or empty argument
080: * @exception OpenDataException when the items do not match the
081: * CompositeType
082: */
083: public CompositeDataSupport(CompositeType compositeType,
084: String[] itemNames, Object[] itemValues)
085: throws OpenDataException {
086: if (compositeType == null)
087: throw new IllegalArgumentException("null compositeType");
088: if (itemNames == null)
089: throw new IllegalArgumentException("null itemNames");
090: if (itemValues == null)
091: throw new IllegalArgumentException("null itemValues");
092: if (itemNames.length == 0)
093: throw new IllegalArgumentException("empty itemNames");
094: if (itemValues.length == 0)
095: throw new IllegalArgumentException("empty itemValues");
096: if (itemNames.length != itemValues.length)
097: throw new IllegalArgumentException("itemNames has size "
098: + itemNames.length + " but itemValues has size "
099: + itemValues.length);
100: int compositeNameSize = compositeType.keySet().size();
101: if (itemNames.length != compositeNameSize)
102: throw new OpenDataException("itemNames has size "
103: + itemNames.length
104: + " but composite type has size "
105: + compositeNameSize);
106:
107: this .compositeType = compositeType;
108: contents = new TreeMap();
109:
110: for (int i = 0; i < itemNames.length; i++) {
111: if (itemNames[i] == null || itemNames[i].length() == 0)
112: throw new IllegalArgumentException("Item name " + i
113: + " is null or empty");
114: if (contents.get(itemNames[i]) != null)
115: throw new OpenDataException("duplicate item name "
116: + itemNames[i]);
117: OpenType openType = compositeType.getType(itemNames[i]);
118: if (openType == null)
119: throw new OpenDataException(
120: "item name not in composite type "
121: + itemNames[i]);
122: if (itemValues[i] != null
123: && openType.isValue(itemValues[i]) == false)
124: throw new OpenDataException("item value "
125: + itemValues[i] + " for item name "
126: + itemNames[i] + " is not a " + openType);
127: contents.put(itemNames[i], itemValues[i]);
128: }
129: }
130:
131: /**
132: * Construct Composite Data
133: *
134: * @param compositeType the composite type of the data
135: * @param items map of strings to values
136: * @exception IllegalArgumentException for a null or empty argument
137: * @exception OpenDataException when the items do not match the
138: * CompositeType
139: * @exception ArrayStoreException when a key to the map is not a String
140: */
141: public CompositeDataSupport(CompositeType compositeType, Map items)
142: throws OpenDataException {
143: init(compositeType, items);
144: }
145:
146: // Public --------------------------------------------------------
147:
148: // Composite Data Implementation ---------------------------------
149:
150: public CompositeType getCompositeType() {
151: return compositeType;
152: }
153:
154: public Object get(String key) {
155: validateKey(key);
156: return contents.get(key);
157: }
158:
159: /**
160: * Returns an array of the values of the items whose names are specified by keys, in the same order as keys.
161: */
162: public Object[] getAll(String[] keys) {
163: if (keys == null)
164: throw new IllegalArgumentException("Null keys");
165:
166: Object[] result = new Object[keys.length];
167: for (int i = 0; i < keys.length; i++) {
168: validateKey(keys[i]);
169: result[i] = contents.get(keys[i]);
170: }
171: return result;
172: }
173:
174: public boolean containsKey(String key) {
175: if (key == null || key.length() == 0)
176: return false;
177: return contents.containsKey(key);
178: }
179:
180: public boolean containsValue(Object value) {
181: return contents.containsValue(value);
182: }
183:
184: public Collection values() {
185: return Collections.unmodifiableCollection(contents.values());
186: }
187:
188: // Serializable Implementation -----------------------------------
189:
190: private void readObject(ObjectInputStream in) throws IOException,
191: ClassNotFoundException {
192: ObjectInputStream.GetField getField = in.readFields();
193: SortedMap contents = (SortedMap) getField.get("contents", null);
194: CompositeType compositeType = (CompositeType) getField.get(
195: "compositeType", null);
196: try {
197: init(compositeType, contents);
198: } catch (Exception e) {
199: throw new StreamCorruptedException(e.toString());
200: }
201: }
202:
203: // Object Overrides ----------------------------------------------
204:
205: public boolean equals(Object obj) {
206: if (obj == null || (obj instanceof CompositeData) == false)
207: return false;
208: if (obj == this )
209: return true;
210:
211: CompositeData other = (CompositeData) obj;
212: if (compositeType.equals(other.getCompositeType()) == false)
213: return false;
214: if (values().size() != other.values().size())
215: return false;
216:
217: for (Iterator i = contents.keySet().iterator(); i.hasNext();) {
218: String key = (String) i.next();
219: Object this Value = this .get(key);
220: Object otherValue = other.get(key);
221: if ((this Value == null && otherValue == null || this Value != null
222: && this Value.equals(otherValue)) == false)
223: return false;
224: }
225: return true;
226: }
227:
228: /**
229: * Returns the hash code value for this CompositeDataSupport instance.
230: *
231: * The hash code of a CompositeDataSupport instance is the sum of the hash codes of all elements of information used
232: * in equals comparisons (ie: its composite type and all the item values).
233: *
234: * This ensures that t1.equals(t2) implies that t1.hashCode()==t2.hashCode() for any two CompositeDataSupport
235: * instances t1 and t2, as required by the general contract of the method Object.hashCode .
236: *
237: * However, note that another instance of a class implementing the CompositeData interface may be equal to this
238: * CompositeDataSupport instance as defined by equals(java.lang.Object), but may have a different hash code if it
239: * is calculated differently.
240: */
241: public int hashCode() {
242: if (hashCode != 0)
243: return hashCode;
244:
245: hashCode = compositeType.hashCode();
246: Iterator it = contents.values().iterator();
247: while (it.hasNext()) {
248: Object value = it.next();
249: if (value != null)
250: hashCode += value.hashCode();
251: }
252:
253: return hashCode;
254: }
255:
256: /**
257: * Returns a string representation of this CompositeDataSupport instance.
258: *
259: * The string representation consists of the name of this class (ie javax.management.openmbean.CompositeDataSupport),
260: * the string representation of the composite type of this instance, and the string representation of the contents
261: * (ie list the itemName=itemValue mappings).
262: */
263: public String toString() {
264: StringBuffer buffer = new StringBuffer(getClass().getName());
265: buffer.append(": compositeType=[");
266: buffer.append(getCompositeType());
267: buffer.append("] mappings=[");
268: Iterator keys = compositeType.keySet().iterator();
269: while (keys.hasNext()) {
270: Object key = keys.next();
271: buffer.append(key + "=" + contents.get(key));
272: if (keys.hasNext())
273: buffer.append(",");
274: }
275: buffer.append("]");
276: return buffer.toString();
277: }
278:
279: // Private -------------------------------------------------------
280:
281: /**
282: * Initialise the composite data
283: *
284: * @param compositeType the composite type of the data
285: * @param items map of strings to values
286: * @exception IllegalArgumentException for a null or empty argument
287: * @exception OpenDataException when the items do not match the
288: * CompositeType
289: * @exception ArrayStoreException when a key to the map is not a String
290: */
291: private void init(CompositeType compositeType, Map items)
292: throws OpenDataException {
293: if (compositeType == null)
294: throw new IllegalArgumentException("null compositeType");
295: if (items == null)
296: throw new IllegalArgumentException("null items");
297: if (items.size() == 0)
298: throw new IllegalArgumentException("empty items");
299: int compositeNameSize = compositeType.keySet().size();
300: if (items.size() != compositeNameSize)
301: throw new OpenDataException("items has size "
302: + items.size() + " but composite type has size "
303: + compositeNameSize);
304:
305: this .compositeType = compositeType;
306: contents = new TreeMap();
307:
308: for (Iterator i = items.keySet().iterator(); i.hasNext();) {
309: Object next = i.next();
310: if (next != null && (next instanceof String) == false)
311: throw new ArrayStoreException("key is not a String "
312: + next);
313: String key = (String) next;
314: if (key == null || key.length() == 0)
315: throw new IllegalArgumentException(
316: "Key is null or empty");
317: OpenType openType = compositeType.getType(key);
318: if (openType == null)
319: throw new OpenDataException(
320: "item name not in composite type " + key);
321: Object value = items.get(key);
322: if (value != null && openType.isValue(value) == false)
323: throw new OpenDataException("item value " + value
324: + " for item name " + key + " is not a "
325: + openType);
326: contents.put(key, value);
327: }
328: }
329:
330: /**
331: * Validates the key against the composite type
332: *
333: * @param key the key to check
334: * @exception IllegalArgumentException for a null or empty key
335: * @exception InvalidKeyException if the key not a valid item name for the composite type
336: */
337: private void validateKey(String key) throws InvalidKeyException {
338: if (key == null || key.length() == 0)
339: throw new IllegalArgumentException("null or empty key");
340: if (compositeType.containsKey(key) == false)
341: throw new InvalidKeyException("no such item name " + key
342: + " for composite type " + compositeType);
343: }
344: }
|