1 /*
2 * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.beans;
27
28 import com.sun.beans.TypeResolver;
29
30 import java.lang.ref.Reference;
31 import java.lang.ref.WeakReference;
32 import java.lang.ref.SoftReference;
33
34 import java.lang.reflect.Method;
35
36 import java.util.Enumeration;
37 import java.util.Hashtable;
38
39 /**
40 * The FeatureDescriptor class is the common baseclass for PropertyDescriptor,
41 * EventSetDescriptor, and MethodDescriptor, etc.
42 * <p>
43 * It supports some common information that can be set and retrieved for
44 * any of the introspection descriptors.
45 * <p>
46 * In addition it provides an extension mechanism so that arbitrary
47 * attribute/value pairs can be associated with a design feature.
48 */
49
50 public class FeatureDescriptor {
51 private static final String TRANSIENT = "transient";
52
53 private Reference<Class> classRef;
54
55 /**
56 * Constructs a <code>FeatureDescriptor</code>.
57 */
58 public FeatureDescriptor() {
59 }
60
61 /**
62 * Gets the programmatic name of this feature.
63 *
64 * @return The programmatic name of the property/method/event
65 */
66 public String getName() {
67 return name;
68 }
69
70 /**
71 * Sets the programmatic name of this feature.
72 *
73 * @param name The programmatic name of the property/method/event
74 */
75 public void setName(String name) {
76 this.name = name;
77 }
78
79 /**
80 * Gets the localized display name of this feature.
81 *
82 * @return The localized display name for the property/method/event.
83 * This defaults to the same as its programmatic name from getName.
84 */
85 public String getDisplayName() {
86 if (displayName == null) {
87 return getName();
88 }
89 return displayName;
90 }
91
92 /**
93 * Sets the localized display name of this feature.
94 *
95 * @param displayName The localized display name for the
96 * property/method/event.
97 */
98 public void setDisplayName(String displayName) {
99 this.displayName = displayName;
100 }
101
102 /**
103 * The "expert" flag is used to distinguish between those features that are
104 * intended for expert users from those that are intended for normal users.
105 *
106 * @return True if this feature is intended for use by experts only.
107 */
108 public boolean isExpert() {
109 return expert;
110 }
111
112 /**
113 * The "expert" flag is used to distinguish between features that are
114 * intended for expert users from those that are intended for normal users.
115 *
116 * @param expert True if this feature is intended for use by experts only.
117 */
118 public void setExpert(boolean expert) {
119 this.expert = expert;
120 }
121
122 /**
123 * The "hidden" flag is used to identify features that are intended only
124 * for tool use, and which should not be exposed to humans.
125 *
126 * @return True if this feature should be hidden from human users.
127 */
128 public boolean isHidden() {
129 return hidden;
130 }
131
132 /**
133 * The "hidden" flag is used to identify features that are intended only
134 * for tool use, and which should not be exposed to humans.
135 *
136 * @param hidden True if this feature should be hidden from human users.
137 */
138 public void setHidden(boolean hidden) {
139 this.hidden = hidden;
140 }
141
142 /**
143 * The "preferred" flag is used to identify features that are particularly
144 * important for presenting to humans.
145 *
146 * @return True if this feature should be preferentially shown to human users.
147 */
148 public boolean isPreferred() {
149 return preferred;
150 }
151
152 /**
153 * The "preferred" flag is used to identify features that are particularly
154 * important for presenting to humans.
155 *
156 * @param preferred True if this feature should be preferentially shown
157 * to human users.
158 */
159 public void setPreferred(boolean preferred) {
160 this.preferred = preferred;
161 }
162
163 /**
164 * Gets the short description of this feature.
165 *
166 * @return A localized short description associated with this
167 * property/method/event. This defaults to be the display name.
168 */
169 public String getShortDescription() {
170 if (shortDescription == null) {
171 return getDisplayName();
172 }
173 return shortDescription;
174 }
175
176 /**
177 * You can associate a short descriptive string with a feature. Normally
178 * these descriptive strings should be less than about 40 characters.
179 * @param text A (localized) short description to be associated with
180 * this property/method/event.
181 */
182 public void setShortDescription(String text) {
183 shortDescription = text;
184 }
185
186 /**
187 * Associate a named attribute with this feature.
188 *
189 * @param attributeName The locale-independent name of the attribute
190 * @param value The value.
191 */
192 public void setValue(String attributeName, Object value) {
193 getTable().put(attributeName, value);
194 }
195
196 /**
197 * Retrieve a named attribute with this feature.
198 *
199 * @param attributeName The locale-independent name of the attribute
200 * @return The value of the attribute. May be null if
201 * the attribute is unknown.
202 */
203 public Object getValue(String attributeName) {
204 return (this.table != null)
205 ? this.table.get(attributeName)
206 : null;
207 }
208
209 /**
210 * Gets an enumeration of the locale-independent names of this
211 * feature.
212 *
213 * @return An enumeration of the locale-independent names of any
214 * attributes that have been registered with setValue.
215 */
216 public Enumeration<String> attributeNames() {
217 return getTable().keys();
218 }
219
220 /**
221 * Package-private constructor,
222 * Merge information from two FeatureDescriptors.
223 * The merged hidden and expert flags are formed by or-ing the values.
224 * In the event of other conflicts, the second argument (y) is
225 * given priority over the first argument (x).
226 *
227 * @param x The first (lower priority) MethodDescriptor
228 * @param y The second (higher priority) MethodDescriptor
229 */
230 FeatureDescriptor(FeatureDescriptor x, FeatureDescriptor y) {
231 expert = x.expert | y.expert;
232 hidden = x.hidden | y.hidden;
233 preferred = x.preferred | y.preferred;
234 name = y.name;
235 shortDescription = x.shortDescription;
236 if (y.shortDescription != null) {
237 shortDescription = y.shortDescription;
238 }
239 displayName = x.displayName;
240 if (y.displayName != null) {
241 displayName = y.displayName;
242 }
243 classRef = x.classRef;
244 if (y.classRef != null) {
245 classRef = y.classRef;
246 }
247 addTable(x.table);
248 addTable(y.table);
249 }
250
251 /*
252 * Package-private dup constructor
253 * This must isolate the new object from any changes to the old object.
254 */
255 FeatureDescriptor(FeatureDescriptor old) {
256 expert = old.expert;
257 hidden = old.hidden;
258 preferred = old.preferred;
259 name = old.name;
260 shortDescription = old.shortDescription;
261 displayName = old.displayName;
262 classRef = old.classRef;
263
264 addTable(old.table);
265 }
266
267 /**
268 * Copies all values from the specified attribute table.
269 * If some attribute is exist its value should be overridden.
270 *
271 * @param table the attribute table with new values
272 */
273 private void addTable(Hashtable<String, Object> table) {
274 if ((table != null) && !table.isEmpty()) {
275 getTable().putAll(table);
276 }
277 }
278
279 /**
280 * Returns the initialized attribute table.
281 *
282 * @return the initialized attribute table
283 */
284 private Hashtable<String, Object> getTable() {
285 if (this.table == null) {
286 this.table = new Hashtable<String, Object>();
287 }
288 return this.table;
289 }
290
291 /**
292 * Sets the "transient" attribute according to the annotation.
293 * If the "transient" attribute is already set
294 * it should not be changed.
295 *
296 * @param annotation the annotation of the element of the feature
297 */
298 void setTransient(Transient annotation) {
299 if ((annotation != null) && (null == getValue(TRANSIENT))) {
300 setValue(TRANSIENT, annotation.value());
301 }
302 }
303
304 /**
305 * Indicates whether the feature is transient.
306 *
307 * @return {@code true} if the feature is transient,
308 * {@code false} otherwise
309 */
310 boolean isTransient() {
311 Object value = getValue(TRANSIENT);
312 return (value instanceof Boolean)
313 ? (Boolean) value
314 : false;
315 }
316
317 // Package private methods for recreating the weak/soft referent
318
319 void setClass0(Class cls) {
320 this.classRef = getWeakReference(cls);
321 }
322
323 Class getClass0() {
324 return (this.classRef != null)
325 ? this.classRef.get()
326 : null;
327 }
328
329 /**
330 * Creates a new soft reference that refers to the given object.
331 *
332 * @return a new soft reference or <code>null</code> if object is <code>null</code>
333 *
334 * @see SoftReference
335 */
336 static <T> Reference<T> getSoftReference(T object) {
337 return (object != null)
338 ? new SoftReference<T>(object)
339 : null;
340 }
341
342 /**
343 * Creates a new weak reference that refers to the given object.
344 *
345 * @return a new weak reference or <code>null</code> if object is <code>null</code>
346 *
347 * @see WeakReference
348 */
349 static <T> Reference<T> getWeakReference(T object) {
350 return (object != null)
351 ? new WeakReference<T>(object)
352 : null;
353 }
354
355 /**
356 * Resolves the return type of the method.
357 *
358 * @param base the class that contains the method in the hierarchy
359 * @param method the object that represents the method
360 * @return a class identifying the return type of the method
361 *
362 * @see Method#getGenericReturnType
363 * @see Method#getReturnType
364 */
365 static Class getReturnType(Class base, Method method) {
366 if (base == null) {
367 base = method.getDeclaringClass();
368 }
369 return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericReturnType()));
370 }
371
372 /**
373 * Resolves the parameter types of the method.
374 *
375 * @param base the class that contains the method in the hierarchy
376 * @param method the object that represents the method
377 * @return an array of classes identifying the parameter types of the method
378 *
379 * @see Method#getGenericParameterTypes
380 * @see Method#getParameterTypes
381 */
382 static Class[] getParameterTypes(Class base, Method method) {
383 if (base == null) {
384 base = method.getDeclaringClass();
385 }
386 return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericParameterTypes()));
387 }
388
389 private boolean expert;
390 private boolean hidden;
391 private boolean preferred;
392 private String shortDescription;
393 private String name;
394 private String displayName;
395 private Hashtable<String, Object> table;
396 }