| /* |
| * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package java.beans; |
| |
| import com.sun.beans.TypeResolver; |
| |
| import java.lang.ref.Reference; |
| import java.lang.ref.WeakReference; |
| import java.lang.ref.SoftReference; |
| |
| import java.lang.reflect.Method; |
| |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.Map.Entry; |
| |
| /** |
| * The FeatureDescriptor class is the common baseclass for PropertyDescriptor, |
| * EventSetDescriptor, and MethodDescriptor, etc. |
| * <p> |
| * It supports some common information that can be set and retrieved for |
| * any of the introspection descriptors. |
| * <p> |
| * In addition it provides an extension mechanism so that arbitrary |
| * attribute/value pairs can be associated with a design feature. |
| */ |
| |
| public class FeatureDescriptor { |
| private static final String TRANSIENT = "transient"; |
| |
| private Reference<Class> classRef; |
| |
| /** |
| * Constructs a <code>FeatureDescriptor</code>. |
| */ |
| public FeatureDescriptor() { |
| } |
| |
| /** |
| * Gets the programmatic name of this feature. |
| * |
| * @return The programmatic name of the property/method/event |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * Sets the programmatic name of this feature. |
| * |
| * @param name The programmatic name of the property/method/event |
| */ |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| /** |
| * Gets the localized display name of this feature. |
| * |
| * @return The localized display name for the property/method/event. |
| * This defaults to the same as its programmatic name from getName. |
| */ |
| public String getDisplayName() { |
| if (displayName == null) { |
| return getName(); |
| } |
| return displayName; |
| } |
| |
| /** |
| * Sets the localized display name of this feature. |
| * |
| * @param displayName The localized display name for the |
| * property/method/event. |
| */ |
| public void setDisplayName(String displayName) { |
| this.displayName = displayName; |
| } |
| |
| /** |
| * The "expert" flag is used to distinguish between those features that are |
| * intended for expert users from those that are intended for normal users. |
| * |
| * @return True if this feature is intended for use by experts only. |
| */ |
| public boolean isExpert() { |
| return expert; |
| } |
| |
| /** |
| * The "expert" flag is used to distinguish between features that are |
| * intended for expert users from those that are intended for normal users. |
| * |
| * @param expert True if this feature is intended for use by experts only. |
| */ |
| public void setExpert(boolean expert) { |
| this.expert = expert; |
| } |
| |
| /** |
| * The "hidden" flag is used to identify features that are intended only |
| * for tool use, and which should not be exposed to humans. |
| * |
| * @return True if this feature should be hidden from human users. |
| */ |
| public boolean isHidden() { |
| return hidden; |
| } |
| |
| /** |
| * The "hidden" flag is used to identify features that are intended only |
| * for tool use, and which should not be exposed to humans. |
| * |
| * @param hidden True if this feature should be hidden from human users. |
| */ |
| public void setHidden(boolean hidden) { |
| this.hidden = hidden; |
| } |
| |
| /** |
| * The "preferred" flag is used to identify features that are particularly |
| * important for presenting to humans. |
| * |
| * @return True if this feature should be preferentially shown to human users. |
| */ |
| public boolean isPreferred() { |
| return preferred; |
| } |
| |
| /** |
| * The "preferred" flag is used to identify features that are particularly |
| * important for presenting to humans. |
| * |
| * @param preferred True if this feature should be preferentially shown |
| * to human users. |
| */ |
| public void setPreferred(boolean preferred) { |
| this.preferred = preferred; |
| } |
| |
| /** |
| * Gets the short description of this feature. |
| * |
| * @return A localized short description associated with this |
| * property/method/event. This defaults to be the display name. |
| */ |
| public String getShortDescription() { |
| if (shortDescription == null) { |
| return getDisplayName(); |
| } |
| return shortDescription; |
| } |
| |
| /** |
| * You can associate a short descriptive string with a feature. Normally |
| * these descriptive strings should be less than about 40 characters. |
| * @param text A (localized) short description to be associated with |
| * this property/method/event. |
| */ |
| public void setShortDescription(String text) { |
| shortDescription = text; |
| } |
| |
| /** |
| * Associate a named attribute with this feature. |
| * |
| * @param attributeName The locale-independent name of the attribute |
| * @param value The value. |
| */ |
| public void setValue(String attributeName, Object value) { |
| getTable().put(attributeName, value); |
| } |
| |
| /** |
| * Retrieve a named attribute with this feature. |
| * |
| * @param attributeName The locale-independent name of the attribute |
| * @return The value of the attribute. May be null if |
| * the attribute is unknown. |
| */ |
| public Object getValue(String attributeName) { |
| return (this.table != null) |
| ? this.table.get(attributeName) |
| : null; |
| } |
| |
| /** |
| * Gets an enumeration of the locale-independent names of this |
| * feature. |
| * |
| * @return An enumeration of the locale-independent names of any |
| * attributes that have been registered with setValue. |
| */ |
| public Enumeration<String> attributeNames() { |
| return getTable().keys(); |
| } |
| |
| /** |
| * Package-private constructor, |
| * Merge information from two FeatureDescriptors. |
| * The merged hidden and expert flags are formed by or-ing the values. |
| * In the event of other conflicts, the second argument (y) is |
| * given priority over the first argument (x). |
| * |
| * @param x The first (lower priority) MethodDescriptor |
| * @param y The second (higher priority) MethodDescriptor |
| */ |
| FeatureDescriptor(FeatureDescriptor x, FeatureDescriptor y) { |
| expert = x.expert | y.expert; |
| hidden = x.hidden | y.hidden; |
| preferred = x.preferred | y.preferred; |
| name = y.name; |
| shortDescription = x.shortDescription; |
| if (y.shortDescription != null) { |
| shortDescription = y.shortDescription; |
| } |
| displayName = x.displayName; |
| if (y.displayName != null) { |
| displayName = y.displayName; |
| } |
| classRef = x.classRef; |
| if (y.classRef != null) { |
| classRef = y.classRef; |
| } |
| addTable(x.table); |
| addTable(y.table); |
| } |
| |
| /* |
| * Package-private dup constructor |
| * This must isolate the new object from any changes to the old object. |
| */ |
| FeatureDescriptor(FeatureDescriptor old) { |
| expert = old.expert; |
| hidden = old.hidden; |
| preferred = old.preferred; |
| name = old.name; |
| shortDescription = old.shortDescription; |
| displayName = old.displayName; |
| classRef = old.classRef; |
| |
| addTable(old.table); |
| } |
| |
| /** |
| * Copies all values from the specified attribute table. |
| * If some attribute is exist its value should be overridden. |
| * |
| * @param table the attribute table with new values |
| */ |
| private void addTable(Hashtable<String, Object> table) { |
| if ((table != null) && !table.isEmpty()) { |
| getTable().putAll(table); |
| } |
| } |
| |
| /** |
| * Returns the initialized attribute table. |
| * |
| * @return the initialized attribute table |
| */ |
| private Hashtable<String, Object> getTable() { |
| if (this.table == null) { |
| this.table = new Hashtable<String, Object>(); |
| } |
| return this.table; |
| } |
| |
| /** |
| * Sets the "transient" attribute according to the annotation. |
| * If the "transient" attribute is already set |
| * it should not be changed. |
| * |
| * @param annotation the annotation of the element of the feature |
| */ |
| void setTransient(Transient annotation) { |
| if ((annotation != null) && (null == getValue(TRANSIENT))) { |
| setValue(TRANSIENT, annotation.value()); |
| } |
| } |
| |
| /** |
| * Indicates whether the feature is transient. |
| * |
| * @return {@code true} if the feature is transient, |
| * {@code false} otherwise |
| */ |
| boolean isTransient() { |
| Object value = getValue(TRANSIENT); |
| return (value instanceof Boolean) |
| ? (Boolean) value |
| : false; |
| } |
| |
| // Package private methods for recreating the weak/soft referent |
| |
| void setClass0(Class cls) { |
| this.classRef = getWeakReference(cls); |
| } |
| |
| Class getClass0() { |
| return (this.classRef != null) |
| ? this.classRef.get() |
| : null; |
| } |
| |
| /** |
| * Creates a new soft reference that refers to the given object. |
| * |
| * @return a new soft reference or <code>null</code> if object is <code>null</code> |
| * |
| * @see SoftReference |
| */ |
| static <T> Reference<T> getSoftReference(T object) { |
| return (object != null) |
| ? new SoftReference<T>(object) |
| : null; |
| } |
| |
| /** |
| * Creates a new weak reference that refers to the given object. |
| * |
| * @return a new weak reference or <code>null</code> if object is <code>null</code> |
| * |
| * @see WeakReference |
| */ |
| static <T> Reference<T> getWeakReference(T object) { |
| return (object != null) |
| ? new WeakReference<T>(object) |
| : null; |
| } |
| |
| /** |
| * Resolves the return type of the method. |
| * |
| * @param base the class that contains the method in the hierarchy |
| * @param method the object that represents the method |
| * @return a class identifying the return type of the method |
| * |
| * @see Method#getGenericReturnType |
| * @see Method#getReturnType |
| */ |
| static Class getReturnType(Class base, Method method) { |
| if (base == null) { |
| base = method.getDeclaringClass(); |
| } |
| return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericReturnType())); |
| } |
| |
| /** |
| * Resolves the parameter types of the method. |
| * |
| * @param base the class that contains the method in the hierarchy |
| * @param method the object that represents the method |
| * @return an array of classes identifying the parameter types of the method |
| * |
| * @see Method#getGenericParameterTypes |
| * @see Method#getParameterTypes |
| */ |
| static Class[] getParameterTypes(Class base, Method method) { |
| if (base == null) { |
| base = method.getDeclaringClass(); |
| } |
| return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericParameterTypes())); |
| } |
| |
| private boolean expert; |
| private boolean hidden; |
| private boolean preferred; |
| private String shortDescription; |
| private String name; |
| private String displayName; |
| private Hashtable<String, Object> table; |
| |
| /** |
| * Returns a string representation of the object. |
| * |
| * @return a string representation of the object |
| * |
| * @since 1.7 |
| */ |
| public String toString() { |
| StringBuilder sb = new StringBuilder(getClass().getName()); |
| sb.append("[name=").append(this.name); |
| appendTo(sb, "displayName", this.displayName); |
| appendTo(sb, "shortDescription", this.shortDescription); |
| appendTo(sb, "preferred", this.preferred); |
| appendTo(sb, "hidden", this.hidden); |
| appendTo(sb, "expert", this.expert); |
| if ((this.table != null) && !this.table.isEmpty()) { |
| sb.append("; values={"); |
| for (Entry<String, Object> entry : this.table.entrySet()) { |
| sb.append(entry.getKey()).append("=").append(entry.getValue()).append("; "); |
| } |
| sb.setLength(sb.length() - 2); |
| sb.append("}"); |
| } |
| appendTo(sb); |
| return sb.append("]").toString(); |
| } |
| |
| void appendTo(StringBuilder sb) { |
| } |
| |
| static void appendTo(StringBuilder sb, String name, Reference reference) { |
| if (reference != null) { |
| appendTo(sb, name, reference.get()); |
| } |
| } |
| |
| static void appendTo(StringBuilder sb, String name, Object value) { |
| if (value != null) { |
| sb.append("; ").append(name).append("=").append(value); |
| } |
| } |
| |
| static void appendTo(StringBuilder sb, String name, boolean value) { |
| if (value) { |
| sb.append("; ").append(name); |
| } |
| } |
| } |