KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > openmbean > CompositeDataInvocationHandler


1 /*
2  * @(#)CompositeDataInvocationHandler.java 1.6 05/11/17
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.management.openmbean;
9
10 import com.sun.jmx.mbeanserver.MXBeanLookup;
11 import com.sun.jmx.mbeanserver.OpenConverter;
12 import java.lang.reflect.InvocationHandler JavaDoc;
13 import java.lang.reflect.Method JavaDoc;
14 import java.lang.reflect.Proxy JavaDoc;
15
16 /**
17    <p>An {@link InvocationHandler} that forwards getter methods to a
18    {@link CompositeData}. If you have an interface that contains
19    only getter methods (such as {@code String getName()} or
20    {@code boolean isActive()}) then you can use this class in
21    conjunction with the {@link Proxy} class to produce an implementation
22    of the interface where each getter returns the value of the
23    corresponding item in a {@code CompositeData}.</p>
24
25    <p>For example, suppose you have an interface like this:
26
27    <blockquote>
28    <pre>
29    public interface NamedNumber {
30        public int getNumber();
31        public String getName();
32    }
33    </pre>
34    </blockquote>
35
36    and a {@code CompositeData} constructed like this:
37
38    <blockquote>
39    <pre>
40    CompositeData cd =
41        new {@link CompositeDataSupport}(
42            someCompositeType,
43        new String[] {"number", "name"},
44        new Object[] {<b>5</b>, "five"}
45        );
46    </pre>
47    </blockquote>
48
49    then you can construct an object implementing {@code NamedNumber}
50    and backed by the object {@code cd} like this:
51
52    <blockquote>
53    <pre>
54    InvocationHandler handler =
55        new CompositeDataInvocationHandler(cd);
56    NamedNumber nn = (NamedNumber)
57        Proxy.newProxyInstance(NamedNumber.class.getClassLoader(),
58                               new Class[] {NamedNumber.class},
59                   handler);
60    </pre>
61    </blockquote>
62
63    A call to {@code nn.getNumber()} will then return <b>5</b>.</p>
64
65    <p>If the first letter of the property defined by a getter is a
66    capital, then this handler will look first for an item in the
67    {@code CompositeData} beginning with a capital, then, if that is
68    not found, for an item beginning with the corresponding lowercase
69    letter or code point. For a getter called {@code getNumber()}, the
70    handler will first look for an item called {@code Number}, then for
71    {@code number}. If the getter is called {@code getnumber()}, then
72    the item must be called {@code number}.</p>
73
74    <p>If the method given to {@link #invoke invoke} is the method
75    {@code boolean equals(Object)} inherited from {@code Object}, then
76    it will return true if and only if the argument is a {@code Proxy}
77    whose {@code InvocationHandler} is also a {@code
78    CompositeDataInvocationHandler} and whose backing {@code
79    CompositeData} is equal (not necessarily identical) to this
80    object's. If the method given to {@code invoke} is the method
81    {@code int hashCode()} inherited from {@code Object}, then it will
82    return a value that is consistent with this definition of {@code
83    equals}: if two objects are equal according to {@code equals}, then
84    they will have the same {@code hashCode}.</p>
85
86    @since 1.6
87 */

88 public class CompositeDataInvocationHandler implements InvocationHandler JavaDoc {
89     /**
90        <p>Construct a handler backed by the given {@code
91        CompositeData}.</p>
92
93        @param compositeData the {@code CompositeData} that will supply
94        information to getters.
95
96        @throws IllegalArgumentException if {@code compositeData}
97        is null.
98     */

99     public CompositeDataInvocationHandler(CompositeData JavaDoc compositeData) {
100         this(compositeData, null);
101     }
102     
103     /**
104        <p>Construct a handler backed by the given {@code
105        CompositeData}.</p>
106       
107        @param mbsc the {@code MBeanServerConnection} related to this
108        {@code CompositeData}. This is only relevant if a method in
109        the interface for which this is an invocation handler returns
110        a type that is an MXBean interface. Otherwise, it can be null.
111
112        @param compositeData the {@code CompositeData} that will supply
113        information to getters.
114
115        @throws IllegalArgumentException if {@code compositeData}
116        is null.
117     */

118     CompositeDataInvocationHandler(CompositeData JavaDoc compositeData,
119                                    MXBeanLookup lookup) {
120     if (compositeData == null)
121         throw new IllegalArgumentException JavaDoc("compositeData");
122     this.compositeData = compositeData;
123         this.lookup = lookup;
124     }
125     
126     /**
127        Return the {@code CompositeData} that was supplied to the
128        constructor.
129        @return the {@code CompositeData} that this handler is backed
130        by. This is never null.
131     */

132     public CompositeData JavaDoc getCompositeData() {
133     assert compositeData != null;
134         return compositeData;
135     }
136
137     public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
138         throws Throwable JavaDoc {
139     final String JavaDoc methodName = method.getName();
140
141     // Handle the methods from java.lang.Object
142
if (method.getDeclaringClass() == Object JavaDoc.class) {
143         if (methodName.equals("toString") && args == null)
144         return "Proxy[" + compositeData + "]";
145         else if (methodName.equals("hashCode") && args == null)
146         return compositeData.hashCode() + 0x43444948;
147         else if (methodName.equals("equals") && args.length == 1
148         && method.getParameterTypes()[0] == Object JavaDoc.class)
149         return equals(proxy, args[0]);
150         else {
151         /* Either someone is calling invoke by hand, or
152            it is a non-final method from Object overriden
153            by the generated Proxy. At the time of writing,
154            the only non-final methods in Object that are not
155            handled above are finalize and clone, and these
156            are not overridden in generated proxies. */

157         return method.invoke(this, args);
158         }
159     }
160
161     String JavaDoc propertyName = OpenConverter.propertyName(method);
162     if (propertyName == null) {
163         throw new IllegalArgumentException JavaDoc("Method is not getter: " +
164                            method.getName());
165     }
166     Object JavaDoc openValue;
167     if (compositeData.containsKey(propertyName))
168         openValue = compositeData.get(propertyName);
169     else {
170         String JavaDoc decap = OpenConverter.decapitalize(propertyName);
171         if (compositeData.containsKey(decap))
172         openValue = compositeData.get(decap);
173         else {
174         final String JavaDoc msg =
175             "No CompositeData item " + propertyName +
176             (decap.equals(propertyName) ? "" : " or " + decap) +
177             " to match " + methodName;
178         throw new IllegalArgumentException JavaDoc(msg);
179         }
180     }
181         OpenConverter converter =
182             OpenConverter.toConverter(method.getGenericReturnType());
183     return converter.fromOpenValue(lookup, openValue);
184     }
185     
186     /* This method is called when equals(Object) is
187      * called on our proxy and hence forwarded to us. For example, if we
188      * are a proxy for an interface like this:
189      * public interface GetString {
190      * public String string();
191      * }
192      * then we must compare equal to another CompositeDataInvocationHandler
193      * proxy for the same interface and where string() returns the same value.
194      *
195      * You might think that we should also compare equal to another
196      * object that implements GetString directly rather than using
197      * Proxy, provided that its string() returns the same result as
198      * ours, and in fact an earlier version of this class did that (by
199      * converting the other object into a CompositeData and comparing
200      * that with ours). But in fact that doesn't make a great deal of
201      * sense because there's absolutely no guarantee that the
202      * resulting equals would be reflexive (otherObject.equals(this)
203      * might be false even if this.equals(otherObject) is true), and,
204      * especially, there's no way we could generate a hashCode() that
205      * would be equal to otherObject.hashCode() when
206      * this.equals(otherObject), because we don't know how
207      * otherObject.hashCode() is computed.
208      */

209     private boolean equals(Object JavaDoc proxy, Object JavaDoc other) {
210         if (other == null)
211             return false;
212
213         final Class JavaDoc proxyClass = proxy.getClass();
214         final Class JavaDoc otherClass = other.getClass();
215     if (proxyClass != otherClass)
216         return false;
217     InvocationHandler JavaDoc otherih = Proxy.getInvocationHandler(other);
218     if (!(otherih instanceof CompositeDataInvocationHandler JavaDoc))
219         return false;
220     CompositeDataInvocationHandler JavaDoc othercdih =
221         (CompositeDataInvocationHandler JavaDoc) otherih;
222     return compositeData.equals(othercdih.compositeData);
223     }
224
225     private final CompositeData JavaDoc compositeData;
226     private final MXBeanLookup lookup;
227 }
228
Popular Tags