KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > api > properties > AnnotatedElementMap


1 package org.apache.beehive.controls.api.properties;
2 /*
3  * Copyright 2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * $Header:$
18  */

19
20 import java.io.IOException JavaDoc;
21 import java.lang.annotation.Annotation JavaDoc;
22 import java.lang.annotation.Inherited JavaDoc;
23 import java.lang.reflect.AnnotatedElement JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29
30
31 import org.apache.beehive.controls.api.bean.ControlBean;
32 import org.apache.beehive.controls.api.bean.ControlExtension;
33 import org.apache.beehive.controls.api.bean.ControlInterface;
34
35 /**
36  * The AnnotatedElementMap represents a read-only PropertyMap where property values are
37  * derived from JSR-175 annotations.
38  */

39 public class AnnotatedElementMap extends BaseMap implements PropertyMap,java.io.Serializable JavaDoc
40 {
41     /**
42      * Creates a new PropertyMap that is initialized based upon the type and annotations
43      * associated with an AnnotatedElement.
44      */

45     public AnnotatedElementMap(AnnotatedElement JavaDoc annotElem)
46     {
47         if (annotElem instanceof Class JavaDoc)
48             setMapClass((Class JavaDoc)annotElem);
49         else if (annotElem instanceof Field JavaDoc)
50             setMapClass(((Field JavaDoc)annotElem).getType());
51         else if (annotElem instanceof Method JavaDoc)
52         {
53             Class JavaDoc mapClass = getMethodMapClass((Method JavaDoc)annotElem);
54             setMapClass(mapClass);
55         }
56         else
57             throw new IllegalArgumentException JavaDoc("Unsupported element type: " + annotElem.getClass());
58
59         _annotElem = annotElem;
60     }
61
62     // For methods, make sure we find a declaring class that is a valid
63
// map class. For extended callback methods, we need to walk up a bit
64
// further in the hierarchy.
65

66     Class JavaDoc getMethodMapClass(Method JavaDoc method) {
67
68         Class JavaDoc origMapClass = method.getDeclaringClass();
69         Class JavaDoc mapClass = origMapClass;
70         while (mapClass != null && !isValidMapClass(mapClass)) {
71             mapClass = mapClass.getDeclaringClass();
72         }
73         if (mapClass == null) {
74             mapClass = origMapClass;
75         }
76         return mapClass;
77     }
78
79     boolean isValidMapClass(Class JavaDoc mapClass) {
80         if (ControlBean.class.isAssignableFrom(mapClass))
81         {
82             return true;
83         }
84         else
85         {
86             if (mapClass.isAnnotation() ||
87                 mapClass.isAnnotationPresent(ControlInterface.class) ||
88                 mapClass.isAnnotationPresent(ControlExtension.class)) {
89                 return true;
90             }
91         }
92         return false;
93     }
94
95     /**
96      * Sets the property specifed by 'key' within this map.
97      */

98     public void setProperty(PropertyKey key, Object JavaDoc value)
99     {
100         throw new IllegalStateException JavaDoc("AnnotatedElementMap is a read-only PropertyMap");
101     }
102
103     /**
104      * Returns the property value specified by 'key' within this map.
105      */

106     public Object JavaDoc getProperty(PropertyKey key)
107     {
108         if (!isValidKey(key))
109             throw new IllegalArgumentException JavaDoc("Key " + key + " is not valid for " + _mapClass);
110
111
112         //
113
// Look for the property value on the associated annotated element
114
//
115
Class JavaDoc propertySet = key.getPropertySet();
116         Annotation JavaDoc annot = _annotElem.getAnnotation(propertySet);
117         if (annot != null)
118             return key.extractValue(annot);
119
120         //
121
// If the property supports inheritance and the annotated element is an interface,
122
// then we'll search up the ControlInheritance/Extension hierachy to see if it is
123
// provided higher up the chain.
124
//
125
if (propertySet.isAnnotationPresent(Inherited JavaDoc.class) && _annotElem instanceof Class JavaDoc)
126         {
127             Class JavaDoc controlIntf = (Class JavaDoc)_annotElem;
128             do
129             {
130                 Class JavaDoc [] superIntfs = controlIntf.getInterfaces();
131                 controlIntf = null;
132                 for (int i = 0; i < superIntfs.length; i++)
133                 {
134                     if (superIntfs[i].isAnnotationPresent(ControlInterface.class) ||
135                         superIntfs[i].isAnnotationPresent(ControlExtension.class))
136                     {
137                         controlIntf = superIntfs[i];
138                         annot = controlIntf.getAnnotation(propertySet);
139                         if (annot != null)
140                             return key.extractValue(annot);
141                     }
142                 }
143
144             }
145             while (controlIntf != null);
146         }
147
148         //
149
// Call up to superclass for delegation / default value
150
//
151
return super.getProperty(key);
152     }
153
154     /**
155      * Returns true if the PropertyMap contains one or more values for the specified
156      * PropertySet, false otherwise
157      */

158     public boolean containsPropertySet(Class JavaDoc<? extends Annotation JavaDoc> propertySet)
159     {
160         if (_annotElem.isAnnotationPresent(propertySet))
161             return true;
162
163         //
164
// Call up to superclass for delegation
165
//
166
return super.containsPropertySet(propertySet);
167     }
168
169     /**
170      * Returns the AnnotatedElement used for PropertyMap values.
171      */

172     public AnnotatedElement JavaDoc getAnnotatedElement()
173     {
174         return _annotElem;
175     }
176
177     /**
178      * Returns a String version of method argument lists based upon the method argument types
179      */

180     private String JavaDoc getMethodArgs(Method JavaDoc m)
181     {
182         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
183         Class JavaDoc [] argTypes = m.getParameterTypes();
184         for (int i = 0; i < argTypes.length; i++)
185         {
186             if (i != 0) sb.append(",");
187             sb.append(argTypes[i].toString());
188         }
189         return sb.toString();
190     }
191
192     /**
193      * Overrides the standard Serialization writeObject method to compute and store the element
194      * information in a serializable form.
195      */

196     private void writeObject(java.io.ObjectOutputStream JavaDoc out) throws IOException JavaDoc
197     {
198         //
199
// When serializing, compute sufficient information about the annotated element to
200
// allow it to be reassociated later in readObject
201
//
202
if (_annotElem instanceof Class JavaDoc)
203         {
204             _elemClass = (Class JavaDoc)_annotElem;
205             _elemDesc = null; // non required
206
}
207         else if (_annotElem instanceof Field JavaDoc)
208         {
209             Field JavaDoc f = (Field JavaDoc)_annotElem;
210             _elemClass = f.getDeclaringClass();
211             _elemDesc = f.getName();
212         }
213         else if (_annotElem instanceof Method JavaDoc)
214         {
215             Method JavaDoc m = (Method JavaDoc)_annotElem;
216             _elemClass = m.getDeclaringClass();
217             _elemDesc = m.getName() + "(" + getMethodArgs(m) + ")";
218         }
219
220         out.defaultWriteObject();
221     }
222
223     /**
224      * Overrides the standard Serialization readObject implementation to reassociated with the
225      * target AnnotatedElement after deserialization.
226      */

227     private void readObject(java.io.ObjectInputStream JavaDoc in)
228                  throws IOException JavaDoc, ClassNotFoundException JavaDoc
229     {
230         in.defaultReadObject();
231
232         if (_elemDesc == null) // element is a Class
233
_annotElem = _elemClass;
234         else
235         {
236             int argsIndex = _elemDesc.indexOf('/');
237             if (argsIndex < 0) // element is a Field
238
{
239                 try
240                 {
241                     _annotElem = _elemClass.getDeclaredField(_elemDesc);
242                 }
243                 catch (NoSuchFieldException JavaDoc nsfe)
244                 {
245                     throw new IOException JavaDoc("Unable to locate field " + nsfe);
246                 }
247             }
248             else // element is a method
249
{
250                 String JavaDoc methodName = _elemDesc.substring(0, argsIndex);
251                 if (_elemDesc.charAt(argsIndex+1) == ')')
252                 {
253                     // At least handle the null args case quickly
254
try
255                     {
256                         _annotElem = _elemClass.getDeclaredMethod(methodName, new Class JavaDoc [] {});
257                     }
258                     catch (NoSuchMethodException JavaDoc nsme)
259                     {
260                         throw new IOException JavaDoc("Unable to locate method " +_elemDesc);
261                     }
262                 }
263                 else
264                 {
265                     // Linear search for the rest :(
266
String JavaDoc methodArgs = _elemDesc.substring(argsIndex+1, _elemDesc.length()-1);
267                     Method JavaDoc [] methods = _elemClass.getDeclaredMethods();
268                     for (int i = 0; i < methods.length; i++)
269                     {
270                         if (methods[i].getName().equals(methodName) &&
271                             getMethodArgs(methods[i]).equals(methodArgs))
272                         {
273                             _annotElem = methods[i];
274                             break;
275                         }
276                     }
277
278                     if (_annotElem == null)
279                     {
280                         throw new IOException JavaDoc("Unable to locate method " + _elemDesc);
281                     }
282                 }
283             }
284         }
285     }
286
287     // The AnnotatedElement upon which this PropertyMap is based. This is marked transient,
288
// because many Reflection types are not Serializable.
289
transient private AnnotatedElement JavaDoc _annotElem;
290
291     private Class JavaDoc _elemClass; // Class associated with the annotated element
292
private String JavaDoc _elemDesc; // Description of the element
293
}
294
Popular Tags