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.util.Collections;
025: import java.util.Iterator;
026: import java.util.Set;
027: import java.util.TreeMap;
028: import java.io.Serializable;
029:
030: /**
031: * The CompositeType is an OpenType that describes CompositeData.
032: *
033: * @see CompositeData
034: *
035: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
036: * @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
037: *
038: * @version $Revision: 57200 $
039: */
040: public class CompositeType extends OpenType implements Serializable {
041:
042: // Attributes ----------------------------------------------------
043:
044: /**
045: * Item names to descriptions
046: */
047: private TreeMap nameToDescription;
048:
049: /**
050: * Item names to open types
051: */
052: private TreeMap nameToType;
053:
054: /**
055: * Cached hash code
056: */
057: private transient int cachedHashCode = 0;
058:
059: /**
060: * Cached string representation
061: */
062: private transient String cachedToString = null;
063:
064: // Static --------------------------------------------------------
065:
066: private static final long serialVersionUID = -5366242454346948798L;
067:
068: // Constructors --------------------------------------------------
069:
070: /**
071: * Construct a composite type. The parameters are checked for validity.<p>
072: *
073: * The three arrays are internally copied. Future changes to these
074: * arrays do not alter the composite type.<p>
075: *
076: * getClassName() returns javax.management.openbean.CompositeData<p>
077: *
078: * @param typeName the name of the composite type, cannot be null or
079: * empty
080: * @param description the human readable description of the composite type,
081: * cannot be null or empty
082: * @param itemNames the names of the items described by this type. Cannot
083: * be null, must contain at least one element, the elements cannot
084: * be null or empty. The order of the items is unimportant when
085: * determining equality.
086: * @param itemDescriptions the human readable descriptions of the items
087: * in the same order as the itemNames, cannot be null must have the
088: * same number of elements as the itemNames. The elements cannot
089: * be null or empty.
090: * @param itemTypes the OpenTypes of the items in the same order as the
091: * item names, cannot be null must have the
092: * same number of elements as the itemNames. The elements cannot
093: * be null.
094: * @exception OpenDataException when itemNames contains a duplicate name.
095: * The names are case sensitive, leading and trailing whitespace
096: * is ignored.
097: * @exception IllegalArgumentException when a parameter does not match
098: * what is described above.
099: */
100: public CompositeType(String typeName, String description,
101: String[] itemNames, String[] itemDescriptions,
102: OpenType[] itemTypes) throws OpenDataException {
103: super (CompositeData.class.getName(), typeName, description);
104: if (itemNames == null || itemNames.length == 0)
105: throw new IllegalArgumentException(
106: "null or empty itemNames");
107: if (itemDescriptions == null || itemDescriptions.length == 0)
108: throw new IllegalArgumentException(
109: "null or empty itemDescriptions");
110: if (itemTypes == null || itemTypes.length == 0)
111: throw new IllegalArgumentException(
112: "null or empty itemTypes");
113: if (itemNames.length != itemDescriptions.length)
114: throw new IllegalArgumentException(
115: "wrong number of itemDescriptions");
116: if (itemNames.length != itemTypes.length)
117: throw new IllegalArgumentException(
118: "wrong number of itemTypes");
119: nameToDescription = new TreeMap();
120: nameToType = new TreeMap();
121: for (int i = 0; i < itemNames.length; i++) {
122: if (itemNames[i] == null)
123: throw new IllegalArgumentException("null item name "
124: + i);
125: String itemName = itemNames[i].trim();
126: if (itemName.length() == 0)
127: throw new IllegalArgumentException("empty item name "
128: + i);
129: if (nameToDescription.containsKey(itemName))
130: throw new OpenDataException("duplicate item name "
131: + itemName);
132: if (itemDescriptions[i] == null)
133: throw new IllegalArgumentException(
134: "null item description " + i);
135: String itemDescription = itemDescriptions[i].trim();
136: if (itemDescription.length() == 0)
137: throw new IllegalArgumentException(
138: "empty item description " + i);
139: if (itemTypes[i] == null)
140: throw new IllegalArgumentException("null item type "
141: + i);
142: nameToDescription.put(itemName, itemDescription);
143: nameToType.put(itemName, itemTypes[i]);
144: }
145: }
146:
147: // Public --------------------------------------------------------
148:
149: /**
150: * Determine whether this CompositeType contains the itemName
151: *
152: * @param itemName the item name
153: * @return true when it does, false otherwise
154: */
155: public boolean containsKey(String itemName) {
156: if (itemName == null)
157: return false;
158: return nameToDescription.containsKey(itemName);
159: }
160:
161: /**
162: * Retrieve the description for an item name
163: *
164: * @param itemName the item name
165: * @return the description or null when there is no such item name
166: */
167: public String getDescription(String itemName) {
168: if (itemName == null)
169: return null;
170: return (String) nameToDescription.get(itemName);
171: }
172:
173: /**
174: * Retrieve the open type for an item name
175: *
176: * @param itemName the item name
177: * @return the open type or null when there is no such item name
178: */
179: public OpenType getType(String itemName) {
180: if (itemName == null)
181: return null;
182: return (OpenType) nameToType.get(itemName);
183: }
184:
185: /**
186: * Retrieve an unmodifiable Set view of all the item names in
187: * ascending order.
188: *
189: * @return the Set
190: */
191: public Set keySet() {
192: return Collections.unmodifiableSet(nameToDescription.keySet());
193: }
194:
195: // OpenType Overrides --------------------------------------------
196:
197: /**
198: * Determines whether the object is a value of the this composite type.<p>
199: *
200: * The object must not be null and it must be an instance of
201: * javax.management.openbean.CompositeData. The CompositeType of the
202: * CompositeData have equality with this CompositeType.
203: *
204: * @param obj the object to test
205: * @return the true when the above condition is satisfied, false otherwise
206: */
207: public boolean isValue(Object obj) {
208: if (obj == null || !(obj instanceof CompositeData))
209: return false;
210: return equals(((CompositeData) obj).getCompositeType());
211: }
212:
213: /**
214: * Tests for equality with another composite type<p>
215: *
216: * The type names must be equal.<br>
217: * The item names and types are equal.
218: *
219: * @param obj the other composite type to test
220: * @return the true when the above condition is satisfied, false otherwise
221: */
222: public boolean equals(Object obj) {
223: if (obj == null || (obj instanceof CompositeType) == false)
224: return false;
225: if (this == obj)
226: return true;
227:
228: CompositeType other = (CompositeType) obj;
229: if (this .getTypeName().equals(other.getTypeName()) == false)
230: return false;
231: Iterator this Names = this .keySet().iterator();
232: Iterator otherNames = other.keySet().iterator();
233: while (this Names.hasNext() && otherNames.hasNext()) {
234: String this Name = (String) this Names.next();
235: String otherName = (String) otherNames.next();
236: if (this Name.equals(otherName) == false)
237: return false;
238: if (this .getType(this Name).equals(other.getType(otherName)) == false)
239: return false;
240: }
241: if (this Names.hasNext() || otherNames.hasNext())
242: return false;
243:
244: return true;
245: }
246:
247: public int hashCode() {
248: if (cachedHashCode != 0)
249: return cachedHashCode;
250: cachedHashCode = getTypeName().hashCode();
251: for (Iterator i = nameToType.values().iterator(); i.hasNext();)
252: cachedHashCode += i.next().hashCode();
253: for (Iterator i = nameToDescription.keySet().iterator(); i
254: .hasNext();)
255: cachedHashCode += i.next().hashCode();
256: return cachedHashCode;
257: }
258:
259: public String toString() {
260: if (cachedToString != null)
261: return cachedToString;
262: StringBuffer buffer = new StringBuffer(getClass().getName());
263: buffer.append("\n");
264: Iterator this Names = keySet().iterator();
265: while (this Names.hasNext()) {
266: String this Name = (String) this Names.next();
267: buffer.append("name=");
268: buffer.append(this Name);
269: buffer.append(" type=");
270: buffer.append(getType(this Name));
271: if (this Names.hasNext())
272: buffer.append("\n");
273: }
274: cachedToString = buffer.toString();
275: return cachedToString;
276: }
277: }
|