/*
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
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<? extends
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<>();
}
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<>(
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<>(
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);
}
}
}