1 /* 2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 import java.util.Map.Entry; 39 40 /** 41 * The FeatureDescriptor class is the common baseclass for PropertyDescriptor, 42 * EventSetDescriptor, and MethodDescriptor, etc. 43 * <p> 44 * It supports some common information that can be set and retrieved for 45 * any of the introspection descriptors. 46 * <p> 47 * In addition it provides an extension mechanism so that arbitrary 48 * attribute/value pairs can be associated with a design feature. 49 * 50 * @since 1.1 51 */ 52 53 public class FeatureDescriptor { 54 private static final String TRANSIENT = "transient"; 55 56 private Reference<? extends Class<?>> classRef; 57 58 /** 59 * Constructs a {@code FeatureDescriptor}. 60 */ 61 public FeatureDescriptor() { 62 } 63 64 /** 65 * Gets the programmatic name of this feature. 66 * 67 * @return The programmatic name of the property/method/event 68 */ 69 public String getName() { 70 return name; 71 } 72 73 /** 74 * Sets the programmatic name of this feature. 75 * 76 * @param name The programmatic name of the property/method/event 77 */ 78 public void setName(String name) { 79 this.name = name; 80 } 81 82 /** 83 * Gets the localized display name of this feature. 84 * 85 * @return The localized display name for the property/method/event. 86 * This defaults to the same as its programmatic name from getName. 87 */ 88 public String getDisplayName() { 89 if (displayName == null) { 90 return getName(); 91 } 92 return displayName; 93 } 94 95 /** 96 * Sets the localized display name of this feature. 97 * 98 * @param displayName The localized display name for the 99 * property/method/event. 100 */ 101 public void setDisplayName(String displayName) { 102 this.displayName = displayName; 103 } 104 105 /** 106 * The "expert" flag is used to distinguish between those features that are 107 * intended for expert users from those that are intended for normal users. 108 * 109 * @return True if this feature is intended for use by experts only. 110 */ 111 public boolean isExpert() { 112 return expert; 113 } 114 115 /** 116 * The "expert" flag is used to distinguish between features that are 117 * intended for expert users from those that are intended for normal users. 118 * 119 * @param expert True if this feature is intended for use by experts only. 120 */ 121 public void setExpert(boolean expert) { 122 this.expert = expert; 123 } 124 125 /** 126 * The "hidden" flag is used to identify features that are intended only 127 * for tool use, and which should not be exposed to humans. 128 * 129 * @return True if this feature should be hidden from human users. 130 */ 131 public boolean isHidden() { 132 return hidden; 133 } 134 135 /** 136 * The "hidden" flag is used to identify features that are intended only 137 * for tool use, and which should not be exposed to humans. 138 * 139 * @param hidden True if this feature should be hidden from human users. 140 */ 141 public void setHidden(boolean hidden) { 142 this.hidden = hidden; 143 } 144 145 /** 146 * The "preferred" flag is used to identify features that are particularly 147 * important for presenting to humans. 148 * 149 * @return True if this feature should be preferentially shown to human users. 150 * @since 1.2 151 */ 152 public boolean isPreferred() { 153 return preferred; 154 } 155 156 /** 157 * The "preferred" flag is used to identify features that are particularly 158 * important for presenting to humans. 159 * 160 * @param preferred True if this feature should be preferentially shown 161 * to human users. 162 * @since 1.2 163 */ 164 public void setPreferred(boolean preferred) { 165 this.preferred = preferred; 166 } 167 168 /** 169 * Gets the short description of this feature. 170 * 171 * @return A localized short description associated with this 172 * property/method/event. This defaults to be the display name. 173 */ 174 public String getShortDescription() { 175 if (shortDescription == null) { 176 return getDisplayName(); 177 } 178 return shortDescription; 179 } 180 181 /** 182 * You can associate a short descriptive string with a feature. Normally 183 * these descriptive strings should be less than about 40 characters. 184 * @param text A (localized) short description to be associated with 185 * this property/method/event. 186 */ 187 public void setShortDescription(String text) { 188 shortDescription = text; 189 } 190 191 /** 192 * Associate a named attribute with this feature. 193 * 194 * @param attributeName The locale-independent name of the attribute 195 * @param value The value. 196 */ 197 public void setValue(String attributeName, Object value) { 198 getTable().put(attributeName, value); 199 } 200 201 /** 202 * Retrieve a named attribute with this feature. 203 * 204 * @param attributeName The locale-independent name of the attribute 205 * @return The value of the attribute. May be null if 206 * the attribute is unknown. 207 */ 208 public Object getValue(String attributeName) { 209 return (this.table != null) 210 ? this.table.get(attributeName) 211 : null; 212 } 213 214 /** 215 * Gets an enumeration of the locale-independent names of this 216 * feature. 217 * 218 * @return An enumeration of the locale-independent names of any 219 * attributes that have been registered with setValue. 220 */ 221 public Enumeration<String> attributeNames() { 222 return getTable().keys(); 223 } 224 225 /** 226 * Package-private constructor, 227 * Merge information from two FeatureDescriptors. 228 * The merged hidden and expert flags are formed by or-ing the values. 229 * In the event of other conflicts, the second argument (y) is 230 * given priority over the first argument (x). 231 * 232 * @param x The first (lower priority) MethodDescriptor 233 * @param y The second (higher priority) MethodDescriptor 234 */ 235 FeatureDescriptor(FeatureDescriptor x, FeatureDescriptor y) { 236 expert = x.expert | y.expert; 237 hidden = x.hidden | y.hidden; 238 preferred = x.preferred | y.preferred; 239 name = y.name; 240 shortDescription = x.shortDescription; 241 if (y.shortDescription != null) { 242 shortDescription = y.shortDescription; 243 } 244 displayName = x.displayName; 245 if (y.displayName != null) { 246 displayName = y.displayName; 247 } 248 classRef = x.classRef; 249 if (y.classRef != null) { 250 classRef = y.classRef; 251 } 252 addTable(x.table); 253 addTable(y.table); 254 } 255 256 /* 257 * Package-private dup constructor 258 * This must isolate the new object from any changes to the old object. 259 */ 260 FeatureDescriptor(FeatureDescriptor old) { 261 expert = old.expert; 262 hidden = old.hidden; 263 preferred = old.preferred; 264 name = old.name; 265 shortDescription = old.shortDescription; 266 displayName = old.displayName; 267 classRef = old.classRef; 268 269 addTable(old.table); 270 } 271 272 /** 273 * Copies all values from the specified attribute table. 274 * If some attribute is exist its value should be overridden. 275 * 276 * @param table the attribute table with new values 277 */ 278 private void addTable(Hashtable<String, Object> table) { 279 if ((table != null) && !table.isEmpty()) { 280 getTable().putAll(table); 281 } 282 } 283 284 /** 285 * Returns the initialized attribute table. 286 * 287 * @return the initialized attribute table 288 */ 289 private Hashtable<String, Object> getTable() { 290 if (this.table == null) { 291 this.table = new Hashtable<>(); 292 } 293 return this.table; 294 } 295 296 /** 297 * Sets the "transient" attribute according to the annotation. 298 * If the "transient" attribute is already set 299 * it should not be changed. 300 * 301 * @param annotation the annotation of the element of the feature 302 */ 303 void setTransient(Transient annotation) { 304 if ((annotation != null) && (null == getValue(TRANSIENT))) { 305 setValue(TRANSIENT, annotation.value()); 306 } 307 } 308 309 /** 310 * Indicates whether the feature is transient. 311 * 312 * @return {@code true} if the feature is transient, 313 * {@code false} otherwise 314 */ 315 boolean isTransient() { 316 Object value = getValue(TRANSIENT); 317 return (value instanceof Boolean) 318 ? (Boolean) value 319 : false; 320 } 321 322 // Package private methods for recreating the weak/soft referent 323 324 void setClass0(Class<?> cls) { 325 this.classRef = getWeakReference(cls); 326 } 327 328 Class<?> getClass0() { 329 return (this.classRef != null) 330 ? this.classRef.get() 331 : null; 332 } 333 334 /** 335 * Creates a new soft reference that refers to the given object. 336 * 337 * @return a new soft reference or {@code null} if object is {@code null} 338 * 339 * @see SoftReference 340 */ 341 static <T> Reference<T> getSoftReference(T object) { 342 return (object != null) 343 ? new SoftReference<>(object) 344 : null; 345 } 346 347 /** 348 * Creates a new weak reference that refers to the given object. 349 * 350 * @return a new weak reference or {@code null} if object is {@code null} 351 * 352 * @see WeakReference 353 */ 354 static <T> Reference<T> getWeakReference(T object) { 355 return (object != null) 356 ? new WeakReference<>(object) 357 : null; 358 } 359 360 /** 361 * Resolves the return type of the method. 362 * 363 * @param base the class that contains the method in the hierarchy 364 * @param method the object that represents the method 365 * @return a class identifying the return type of the method 366 * 367 * @see Method#getGenericReturnType 368 * @see Method#getReturnType 369 */ 370 static Class<?> getReturnType(Class<?> base, Method method) { 371 if (base == null) { 372 base = method.getDeclaringClass(); 373 } 374 return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericReturnType())); 375 } 376 377 /** 378 * Resolves the parameter types of the method. 379 * 380 * @param base the class that contains the method in the hierarchy 381 * @param method the object that represents the method 382 * @return an array of classes identifying the parameter types of the method 383 * 384 * @see Method#getGenericParameterTypes 385 * @see Method#getParameterTypes 386 */ 387 static Class<?>[] getParameterTypes(Class<?> base, Method method) { 388 if (base == null) { 389 base = method.getDeclaringClass(); 390 } 391 return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericParameterTypes())); 392 } 393 394 private boolean expert; 395 private boolean hidden; 396 private boolean preferred; 397 private String shortDescription; 398 private String name; 399 private String displayName; 400 private Hashtable<String, Object> table; 401 402 /** 403 * Returns a string representation of the object. 404 * 405 * @return a string representation of the object 406 * 407 * @since 1.7 408 */ 409 public String toString() { 410 StringBuilder sb = new StringBuilder(getClass().getName()); 411 sb.append("[name=").append(this.name); 412 appendTo(sb, "displayName", this.displayName); 413 appendTo(sb, "shortDescription", this.shortDescription); 414 appendTo(sb, "preferred", this.preferred); 415 appendTo(sb, "hidden", this.hidden); 416 appendTo(sb, "expert", this.expert); 417 if ((this.table != null) && !this.table.isEmpty()) { 418 sb.append("; values={"); 419 for (Entry<String, Object> entry : this.table.entrySet()) { 420 sb.append(entry.getKey()).append("=").append(entry.getValue()).append("; "); 421 } 422 sb.setLength(sb.length() - 2); 423 sb.append("}"); 424 } 425 appendTo(sb); 426 return sb.append("]").toString(); 427 } 428 429 void appendTo(StringBuilder sb) { 430 } 431 432 static void appendTo(StringBuilder sb, String name, Reference<?> reference) { 433 if (reference != null) { 434 appendTo(sb, name, reference.get()); 435 } 436 } 437 438 static void appendTo(StringBuilder sb, String name, Object value) { 439 if (value != null) { 440 sb.append("; ").append(name).append("=").append(value); 441 } 442 } 443 444 static void appendTo(StringBuilder sb, String name, boolean value) { 445 if (value) { 446 sb.append("; ").append(name); 447 } 448 } 449 } --- EOF ---