Source Code Cross Referenced for ImmutableDescriptor.java in  » 6.0-JDK-Core » management » javax » management » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » management » javax.management 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2004-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package javax.management;
027
028        import java.io.InvalidObjectException;
029        import java.lang.reflect.Array;
030        import java.util.Arrays;
031        import java.util.Comparator;
032        import java.util.Map;
033        import java.util.SortedMap;
034        import java.util.TreeMap;
035
036        /**
037         * An immutable descriptor.
038         * @since 1.6
039         */
040        public class ImmutableDescriptor implements  Descriptor {
041            private static final long serialVersionUID = 8853308591080540165L;
042
043            /**
044             * The names of the fields in this ImmutableDescriptor with their
045             * original case.  The names must be in alphabetical order as determined
046             * by {@link String#CASE_INSENSITIVE_ORDER}.
047             */
048            private final String[] names;
049            /**
050             * The values of the fields in this ImmutableDescriptor.  The
051             * elements in this array match the corresponding elements in the
052             * {@code names} array.
053             */
054            private final Object[] values;
055
056            private transient int hashCode = -1;
057
058            /**
059             * An empty descriptor.
060             */
061            public static final ImmutableDescriptor EMPTY_DESCRIPTOR = new ImmutableDescriptor();
062
063            /**
064             * Construct a descriptor containing the given fields and values.
065             *
066             * @throws IllegalArgumentException if either array is null, or
067             * if the arrays have different sizes, or
068             * if a field name is null or empty, or if the same field name
069             * appears more than once.
070             */
071            public ImmutableDescriptor(String[] fieldNames, Object[] fieldValues) {
072                this (makeMap(fieldNames, fieldValues));
073            }
074
075            /**
076             * Construct a descriptor containing the given fields.  Each String
077             * must be of the form {@code fieldName=fieldValue}.  The field name
078             * ends at the first {@code =} character; for example if the String
079             * is {@code a=b=c} then the field name is {@code a} and its value
080             * is {@code b=c}.
081             *
082             * @throws IllegalArgumentException if the parameter is null, or
083             * if a field name is empty, or if the same field name appears
084             * more than once, or if one of the strings does not contain
085             * an {@code =} character.
086             */
087            public ImmutableDescriptor(String... fields) {
088                this (makeMap(fields));
089            }
090
091            /**
092             * <p>Construct a descriptor where the names and values of the fields
093             * are the keys and values of the given Map.</p>
094             *
095             * @throws IllegalArgumentException if the parameter is null, or
096             * if a field name is null or empty, or if the same field name appears
097             * more than once (which can happen because field names are not case
098             * sensitive).
099             */
100            public ImmutableDescriptor(Map<String, ?> fields) {
101                if (fields == null)
102                    throw new IllegalArgumentException("Null Map");
103                SortedMap<String, Object> map = new TreeMap<String, Object>(
104                        String.CASE_INSENSITIVE_ORDER);
105                for (Map.Entry<String, ?> entry : fields.entrySet()) {
106                    String name = entry.getKey();
107                    if (name == null || name.equals(""))
108                        throw new IllegalArgumentException(
109                                "Empty or null field name");
110                    if (map.containsKey(name))
111                        throw new IllegalArgumentException("Duplicate name: "
112                                + name);
113                    map.put(name, entry.getValue());
114                }
115                int size = map.size();
116                this .names = map.keySet().toArray(new String[size]);
117                this .values = map.values().toArray(new Object[size]);
118            }
119
120            /**
121             * This method can replace a deserialized instance of this
122             * class with another instance.  For example, it might replace
123             * a deserialized empty ImmutableDescriptor with
124             * {@link #EMPTY_DESCRIPTOR}.
125             *
126             * @return the replacement object, which may be {@code this}.
127             *
128             * @throws InvalidObjectException if the read object has invalid fields.
129             */
130            private Object readResolve() throws InvalidObjectException {
131                if (names.length == 0
132                        && getClass() == ImmutableDescriptor.class)
133                    return EMPTY_DESCRIPTOR;
134
135                boolean bad = false;
136                if (names == null || values == null
137                        || names.length != values.length)
138                    bad = true;
139                if (!bad) {
140                    final Comparator<String> compare = String.CASE_INSENSITIVE_ORDER;
141                    String lastName = ""; // also catches illegal null name
142                    for (int i = 0; i < names.length; i++) {
143                        if (names[i] == null
144                                || compare.compare(lastName, names[i]) >= 0) {
145                            bad = true;
146                            break;
147                        }
148                        lastName = names[i];
149                    }
150                }
151                if (bad)
152                    throw new InvalidObjectException("Bad names or values");
153
154                return this ;
155            }
156
157            private static SortedMap<String, ?> makeMap(String[] fieldNames,
158                    Object[] fieldValues) {
159                if (fieldNames == null || fieldValues == null)
160                    throw new IllegalArgumentException("Null array parameter");
161                if (fieldNames.length != fieldValues.length)
162                    throw new IllegalArgumentException("Different size arrays");
163                SortedMap<String, Object> map = new TreeMap<String, Object>(
164                        String.CASE_INSENSITIVE_ORDER);
165                for (int i = 0; i < fieldNames.length; i++) {
166                    String name = fieldNames[i];
167                    if (name == null || name.equals(""))
168                        throw new IllegalArgumentException(
169                                "Empty or null field name");
170                    Object old = map.put(name, fieldValues[i]);
171                    if (old != null) {
172                        throw new IllegalArgumentException(
173                                "Duplicate field name: " + name);
174                    }
175                }
176                return map;
177            }
178
179            private static SortedMap<String, ?> makeMap(String[] fields) {
180                if (fields == null)
181                    throw new IllegalArgumentException("Null fields parameter");
182                String[] fieldNames = new String[fields.length];
183                String[] fieldValues = new String[fields.length];
184                for (int i = 0; i < fields.length; i++) {
185                    String field = fields[i];
186                    int eq = field.indexOf('=');
187                    if (eq < 0) {
188                        throw new IllegalArgumentException(
189                                "Missing = character: " + field);
190                    }
191                    fieldNames[i] = field.substring(0, eq);
192                    // makeMap will catch the case where the name is empty
193                    fieldValues[i] = field.substring(eq + 1);
194                }
195                return makeMap(fieldNames, fieldValues);
196            }
197
198            /**
199             * <p>Return an {@code ImmutableDescriptor} whose contents are the union of
200             * the given descriptors.  Every field name that appears in any of
201             * the descriptors will appear in the result with the
202             * value that it has when the method is called.  Subsequent changes
203             * to any of the descriptors do not affect the ImmutableDescriptor
204             * returned here.</p>
205             *
206             * <p>In the simplest case, there is only one descriptor and the
207             * returned {@code ImmutableDescriptor} is a copy of its fields at the
208             * time this method is called:</p>
209             *
210             * <pre>
211             * Descriptor d = something();
212             * ImmutableDescriptor copy = ImmutableDescriptor.union(d);
213             * </pre>
214             *
215             * @param descriptors the descriptors to be combined.  Any of the
216             * descriptors can be null, in which case it is skipped.
217             *
218             * @return an {@code ImmutableDescriptor} that is the union of the given
219             * descriptors.  The returned object may be identical to one of the
220             * input descriptors if it is an ImmutableDescriptor that contains all of
221             * the required fields.
222             *
223             * @throws IllegalArgumentException if two Descriptors contain the
224             * same field name with different associated values.  Primitive array
225             * values are considered the same if they are of the same type with
226             * the same elements.  Object array values are considered the same if
227             * {@link Arrays#deepEquals(Object[],Object[])} returns true.
228             */
229            public static ImmutableDescriptor union(Descriptor... descriptors) {
230                // Optimize the case where exactly one Descriptor is non-Empty
231                // and it is immutable - we can just return it.
232                int index = findNonEmpty(descriptors, 0);
233                if (index < 0)
234                    return EMPTY_DESCRIPTOR;
235                if (descriptors[index] instanceof  ImmutableDescriptor
236                        && findNonEmpty(descriptors, index + 1) < 0)
237                    return (ImmutableDescriptor) descriptors[index];
238
239                Map<String, Object> map = new TreeMap<String, Object>(
240                        String.CASE_INSENSITIVE_ORDER);
241                ImmutableDescriptor biggestImmutable = EMPTY_DESCRIPTOR;
242                for (Descriptor d : descriptors) {
243                    if (d != null) {
244                        String[] names;
245                        if (d instanceof  ImmutableDescriptor) {
246                            ImmutableDescriptor id = (ImmutableDescriptor) d;
247                            names = id.names;
248                            if (id.getClass() == ImmutableDescriptor.class
249                                    && names.length > biggestImmutable.names.length)
250                                biggestImmutable = id;
251                        } else
252                            names = d.getFieldNames();
253                        for (String n : names) {
254                            Object v = d.getFieldValue(n);
255                            Object old = map.put(n, v);
256                            if (old != null) {
257                                boolean equal;
258                                if (old.getClass().isArray()) {
259                                    equal = Arrays.deepEquals(
260                                            new Object[] { old },
261                                            new Object[] { v });
262                                } else
263                                    equal = old.equals(v);
264                                if (!equal) {
265                                    final String msg = "Inconsistent values for descriptor field "
266                                            + n + ": " + old + " :: " + v;
267                                    throw new IllegalArgumentException(msg);
268                                }
269                            }
270                        }
271                    }
272                }
273                if (biggestImmutable.names.length == map.size())
274                    return biggestImmutable;
275                return new ImmutableDescriptor(map);
276            }
277
278            private static boolean isEmpty(Descriptor d) {
279                if (d == null)
280                    return true;
281                else if (d instanceof  ImmutableDescriptor)
282                    return ((ImmutableDescriptor) d).names.length == 0;
283                else
284                    return (d.getFieldNames().length == 0);
285            }
286
287            private static int findNonEmpty(Descriptor[] ds, int start) {
288                for (int i = start; i < ds.length; i++) {
289                    if (!isEmpty(ds[i]))
290                        return i;
291                }
292                return -1;
293            }
294
295            private int fieldIndex(String name) {
296                return Arrays.binarySearch(names, name,
297                        String.CASE_INSENSITIVE_ORDER);
298            }
299
300            public final Object getFieldValue(String fieldName) {
301                checkIllegalFieldName(fieldName);
302                int i = fieldIndex(fieldName);
303                if (i < 0)
304                    return null;
305                Object v = values[i];
306                if (v == null || !v.getClass().isArray())
307                    return v;
308                if (v instanceof  Object[])
309                    return ((Object[]) v).clone();
310                // clone the primitive array, could use an 8-way if/else here
311                int len = Array.getLength(v);
312                Object a = Array.newInstance(v.getClass().getComponentType(),
313                        len);
314                System.arraycopy(v, 0, a, 0, len);
315                return a;
316            }
317
318            public final String[] getFields() {
319                String[] result = new String[names.length];
320                for (int i = 0; i < result.length; i++) {
321                    Object value = values[i];
322                    if (value == null)
323                        value = "";
324                    else if (!(value instanceof  String))
325                        value = "(" + value + ")";
326                    result[i] = names[i] + "=" + value;
327                }
328                return result;
329            }
330
331            public final Object[] getFieldValues(String... fieldNames) {
332                if (fieldNames == null)
333                    return values.clone();
334                Object[] result = new Object[fieldNames.length];
335                for (int i = 0; i < fieldNames.length; i++) {
336                    String name = fieldNames[i];
337                    if (name != null && !name.equals(""))
338                        result[i] = getFieldValue(name);
339                }
340                return result;
341            }
342
343            public final String[] getFieldNames() {
344                return names.clone();
345            }
346
347            /**
348             * Compares this descriptor to the given object.  The objects are equal if
349             * the given object is also a Descriptor, and if the two Descriptors have
350             * the same field names (possibly differing in case) and the same
351             * associated values.  The respective values for a field in the two
352             * Descriptors are equal if the following conditions hold:</p>
353             * 
354             * <ul>
355             * <li>If one value is null then the other must be too.</li>
356             * <li>If one value is a primitive array then the other must be a primitive
357             * array of the same type with the same elements.</li>
358             * <li>If one value is an object array then the other must be too and
359             * {@link Arrays#deepEquals(Object[],Object[])} must return true.</li>
360             * <li>Otherwise {@link Object#equals(Object)} must return true.</li>
361             * </ul>
362             *
363             * @param o the object to compare with.
364             *
365             * @return {@code true} if the objects are the same; {@code false}
366             * otherwise.
367             *
368             */
369            // Note: this Javadoc is copied from javax.management.Descriptor
370            //       due to 6369229.
371            public boolean equals(Object o) {
372                if (o == this )
373                    return true;
374                if (!(o instanceof  Descriptor))
375                    return false;
376                String[] onames;
377                if (o instanceof  ImmutableDescriptor) {
378                    onames = ((ImmutableDescriptor) o).names;
379                } else {
380                    onames = ((Descriptor) o).getFieldNames();
381                    Arrays.sort(onames, String.CASE_INSENSITIVE_ORDER);
382                }
383                if (names.length != onames.length)
384                    return false;
385                for (int i = 0; i < names.length; i++) {
386                    if (!names[i].equalsIgnoreCase(onames[i]))
387                        return false;
388                }
389                Object[] ovalues;
390                if (o instanceof  ImmutableDescriptor)
391                    ovalues = ((ImmutableDescriptor) o).values;
392                else
393                    ovalues = ((Descriptor) o).getFieldValues(onames);
394                return Arrays.deepEquals(values, ovalues);
395            }
396
397            /**
398             * <p>Returns the hash code value for this descriptor.  The hash
399             * code is computed as the sum of the hash codes for each field in
400             * the descriptor.  The hash code of a field with name {@code n}
401             * and value {@code v} is {@code n.toLowerCase().hashCode() ^ h}.
402             * Here {@code h} is the hash code of {@code v}, computed as
403             * follows:</p>
404             * 
405             * <ul>
406             * <li>If {@code v} is null then {@code h} is 0.</li>
407             * <li>If {@code v} is a primitive array then {@code h} is computed using
408             * the appropriate overloading of {@code java.util.Arrays.hashCode}.</li>
409             * <li>If {@code v} is an object array then {@code h} is computed using
410             * {@link Arrays#deepHashCode(Object[])}.</li>
411             * <li>Otherwise {@code h} is {@code v.hashCode()}.</li>
412             * </ul>
413             *
414             * @return A hash code value for this object.
415             *
416             */
417            // Note: this Javadoc is copied from javax.management.Descriptor
418            //       due to 6369229.
419            public int hashCode() {
420                if (hashCode == -1) {
421                    int hash = 0;
422                    for (int i = 0; i < names.length; i++) {
423                        Object v = values[i];
424                        int h;
425                        if (v == null)
426                            h = 0;
427                        else if (v instanceof  Object[])
428                            h = Arrays.deepHashCode((Object[]) v);
429                        else if (v.getClass().isArray()) {
430                            h = Arrays.deepHashCode(new Object[] { v }) - 31;
431                            // hashcode of a list containing just v is
432                            // v.hashCode() + 31, see List.hashCode()
433                        } else
434                            h = v.hashCode();
435                        hash += names[i].toLowerCase().hashCode() ^ h;
436                    }
437                    hashCode = hash;
438                }
439                return hashCode;
440            }
441
442            public String toString() {
443                StringBuilder sb = new StringBuilder("{");
444                for (int i = 0; i < names.length; i++) {
445                    if (i > 0)
446                        sb.append(", ");
447                    sb.append(names[i]).append("=");
448                    Object v = values[i];
449                    if (v != null && v.getClass().isArray()) {
450                        String s = Arrays.deepToString(new Object[] { v });
451                        s = s.substring(1, s.length() - 1); // remove [...]
452                        v = s;
453                    }
454                    sb.append(String.valueOf(v));
455                }
456                return sb.append("}").toString();
457            }
458
459            /**
460             * Returns true if all of the fields have legal values given their
461             * names.  This method always returns true, but a subclass can
462             * override it to return false when appropriate.
463             * 
464             * @return true if the values are legal.
465             * 
466             * @exception RuntimeOperationsException if the validity checking fails.
467             * The method returns false if the descriptor is not valid, but throws
468             * this exception if the attempt to determine validity fails.
469             */
470            public boolean isValid() {
471                return true;
472            }
473
474            /**
475             * <p>Returns a descriptor which is equal to this descriptor.
476             * Changes to the returned descriptor will have no effect on this
477             * descriptor, and vice versa.</p>
478             *
479             * <p>This method returns the object on which it is called.
480             * A subclass can override it
481             * to return another object provided the contract is respected.
482             *
483             * @exception RuntimeOperationsException for illegal value for field Names
484             * or field Values.
485             * If the descriptor construction fails for any reason, this exception will
486             * be thrown.
487             */
488            public Descriptor clone() {
489                return this ;
490            }
491
492            /**
493             * This operation is unsupported since this class is immutable.  If
494             * this call would change a mutable descriptor with the same contents,
495             * then a {@link RuntimeOperationsException} wrapping an
496             * {@link UnsupportedOperationException} is thrown.  Otherwise,
497             * the behavior is the same as it would be for a mutable descriptor:
498             * either an exception is thrown because of illegal parameters, or
499             * there is no effect.
500             */
501            public final void setFields(String[] fieldNames,
502                    Object[] fieldValues) throws RuntimeOperationsException {
503                if (fieldNames == null || fieldValues == null)
504                    illegal("Null argument");
505                if (fieldNames.length != fieldValues.length)
506                    illegal("Different array sizes");
507                for (int i = 0; i < fieldNames.length; i++)
508                    checkIllegalFieldName(fieldNames[i]);
509                for (int i = 0; i < fieldNames.length; i++)
510                    setField(fieldNames[i], fieldValues[i]);
511            }
512
513            /**
514             * This operation is unsupported since this class is immutable.  If
515             * this call would change a mutable descriptor with the same contents,
516             * then a {@link RuntimeOperationsException} wrapping an
517             * {@link UnsupportedOperationException} is thrown.  Otherwise,
518             * the behavior is the same as it would be for a mutable descriptor:
519             * either an exception is thrown because of illegal parameters, or
520             * there is no effect.
521             */
522            public final void setField(String fieldName, Object fieldValue)
523                    throws RuntimeOperationsException {
524                checkIllegalFieldName(fieldName);
525                int i = fieldIndex(fieldName);
526                if (i < 0)
527                    unsupported();
528                Object value = values[i];
529                if ((value == null) ? (fieldValue != null) : !value
530                        .equals(fieldValue))
531                    unsupported();
532            }
533
534            /**
535             * Removes a field from the descriptor.
536             *
537             * @param fieldName String name of the field to be removed.
538             * If the field name is illegal or the field is not found,
539             * no exception is thrown.
540             *
541             * @exception RuntimeOperationsException if a field of the given name
542             * exists and the descriptor is immutable.  The wrapped exception will
543             * be an {@link UnsupportedOperationException}.
544             */
545            public final void removeField(String fieldName) {
546                if (fieldName != null && fieldIndex(fieldName) >= 0)
547                    unsupported();
548            }
549
550            static Descriptor nonNullDescriptor(Descriptor d) {
551                if (d == null)
552                    return EMPTY_DESCRIPTOR;
553                else
554                    return d;
555            }
556
557            private static void checkIllegalFieldName(String name) {
558                if (name == null || name.equals(""))
559                    illegal("Null or empty field name");
560            }
561
562            private static void unsupported() {
563                UnsupportedOperationException uoe = new UnsupportedOperationException(
564                        "Descriptor is read-only");
565                throw new RuntimeOperationsException(uoe);
566            }
567
568            private static void illegal(String message) {
569                IllegalArgumentException iae = new IllegalArgumentException(
570                        message);
571                throw new RuntimeOperationsException(iae);
572            }
573        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.