feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 1997, 2013, 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 java.applet.Applet;
import java.beans.beancontext.BeanContext;
/**
* <p>
* This interface is designed to work in collusion with java.beans.Beans.instantiate.
* The interface is intended to provide mechanism to allow the proper
* initialization of JavaBeans that are also Applets, during their
* instantiation by java.beans.Beans.instantiate().
* </p>
*
* @see java.beans.Beans#instantiate
*
* @since 1.2
*
*/
public interface AppletInitializer {
/**
* <p>
* If passed to the appropriate variant of java.beans.Beans.instantiate
* this method will be called in order to associate the newly instantiated
* Applet (JavaBean) with its AppletContext, AppletStub, and Container.
* </p>
* <p>
* Conformant implementations shall:
* <ol>
* <li> Associate the newly instantiated Applet with the appropriate
* AppletContext.
*
* <li> Instantiate an AppletStub() and associate that AppletStub with
* the Applet via an invocation of setStub().
*
* <li> If BeanContext parameter is null, then it shall associate the
* Applet with its appropriate Container by adding that Applet to its
* Container via an invocation of add(). If the BeanContext parameter is
* non-null, then it is the responsibility of the BeanContext to associate
* the Applet with its Container during the subsequent invocation of its
* addChildren() method.
* </ol>
*
* @param newAppletBean The newly instantiated JavaBean
* @param bCtxt The BeanContext intended for this Applet, or
* null.
*/
void initialize(Applet newAppletBean, BeanContext bCtxt);
/**
* <p>
* Activate, and/or mark Applet active. Implementors of this interface
* shall mark this Applet as active, and optionally invoke its start()
* method.
* </p>
*
* @param newApplet The newly instantiated JavaBean
*/
void activate(Applet newApplet);
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 1996, 2011, 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 java.lang.ref.Reference;
/**
* A BeanDescriptor provides global information about a "bean",
* including its Java class, its displayName, etc.
* <p>
* This is one of the kinds of descriptor returned by a BeanInfo object,
* which also returns descriptors for properties, method, and events.
*/
public class BeanDescriptor extends FeatureDescriptor {
private Reference<? extends Class<?>> beanClassRef;
private Reference<? extends Class<?>> customizerClassRef;
/**
* Create a BeanDescriptor for a bean that doesn't have a customizer.
*
* @param beanClass The Class object of the Java class that implements
* the bean. For example sun.beans.OurButton.class.
*/
public BeanDescriptor(Class<?> beanClass) {
this(beanClass, null);
}
/**
* Create a BeanDescriptor for a bean that has a customizer.
*
* @param beanClass The Class object of the Java class that implements
* the bean. For example sun.beans.OurButton.class.
* @param customizerClass The Class object of the Java class that implements
* the bean's Customizer. For example sun.beans.OurButtonCustomizer.class.
*/
public BeanDescriptor(Class<?> beanClass, Class<?> customizerClass) {
this.beanClassRef = getWeakReference(beanClass);
this.customizerClassRef = getWeakReference(customizerClass);
String name = beanClass.getName();
while (name.indexOf('.') >= 0) {
name = name.substring(name.indexOf('.')+1);
}
setName(name);
}
/**
* Gets the bean's Class object.
*
* @return The Class object for the bean.
*/
public Class<?> getBeanClass() {
return (this.beanClassRef != null)
? this.beanClassRef.get()
: null;
}
/**
* Gets the Class object for the bean's customizer.
*
* @return The Class object for the bean's customizer. This may
* be null if the bean doesn't have a customizer.
*/
public Class<?> getCustomizerClass() {
return (this.customizerClassRef != null)
? this.customizerClassRef.get()
: null;
}
/*
* Package-private dup constructor
* This must isolate the new object from any changes to the old object.
*/
BeanDescriptor(BeanDescriptor old) {
super(old);
beanClassRef = old.beanClassRef;
customizerClassRef = old.customizerClassRef;
}
void appendTo(StringBuilder sb) {
appendTo(sb, "beanClass", this.beanClassRef);
appendTo(sb, "customizerClass", this.customizerClassRef);
}
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 1996, 2012, 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 java.awt.Image;
/**
* Use the {@code BeanInfo} interface
* to create a {@code BeanInfo} class
* and provide explicit information about the methods,
* properties, events, and other features of your beans.
* <p>
* When developing your bean, you can implement
* the bean features required for your application task
* omitting the rest of the {@code BeanInfo} features.
* They will be obtained through the automatic analysis
* by using the low-level reflection of the bean methods
* and applying standard design patterns.
* You have an opportunity to provide additional bean information
* through various descriptor classes.
* <p>
* See the {@link SimpleBeanInfo} class that is
* a convenient basic class for {@code BeanInfo} classes.
* You can override the methods and properties of
* the {@code SimpleBeanInfo} class to define specific information.
* <p>
* See also the {@link Introspector} class to learn more about bean behavior.
*/
public interface BeanInfo {
/**
* Returns the bean descriptor
* that provides overall information about the bean,
* such as its display name or its customizer.
*
* @return a {@link BeanDescriptor} object,
* or {@code null} if the information is to
* be obtained through the automatic analysis
*/
BeanDescriptor getBeanDescriptor();
/**
* Returns the event descriptors of the bean
* that define the types of events fired by this bean.
*
* @return an array of {@link EventSetDescriptor} objects,
* or {@code null} if the information is to
* be obtained through the automatic analysis
*/
EventSetDescriptor[] getEventSetDescriptors();
/**
* A bean may have a default event typically applied when this bean is used.
*
* @return index of the default event in the {@code EventSetDescriptor} array
* returned by the {@code getEventSetDescriptors} method,
* or -1 if there is no default event
*/
int getDefaultEventIndex();
/**
* Returns descriptors for all properties of the bean.
* <p>
* If a property is indexed, then its entry in the result array
* belongs to the {@link IndexedPropertyDescriptor} subclass
* of the {@link PropertyDescriptor} class.
* A client of the {@code getPropertyDescriptors} method
* can use the {@code instanceof} operator to check
* whether a given {@code PropertyDescriptor}
* is an {@code IndexedPropertyDescriptor}.
*
* @return an array of {@code PropertyDescriptor} objects,
* or {@code null} if the information is to
* be obtained through the automatic analysis
*/
PropertyDescriptor[] getPropertyDescriptors();
/**
* A bean may have a default property commonly updated when this bean is customized.
*
* @return index of the default property in the {@code PropertyDescriptor} array
* returned by the {@code getPropertyDescriptors} method,
* or -1 if there is no default property
*/
int getDefaultPropertyIndex();
/**
* Returns the method descriptors of the bean
* that define the externally visible methods supported by this bean.
*
* @return an array of {@link MethodDescriptor} objects,
* or {@code null} if the information is to
* be obtained through the automatic analysis
*/
MethodDescriptor[] getMethodDescriptors();
/**
* This method enables the current {@code BeanInfo} object
* to return an arbitrary collection of other {@code BeanInfo} objects
* that provide additional information about the current bean.
* <p>
* If there are conflicts or overlaps between the information
* provided by different {@code BeanInfo} objects,
* the current {@code BeanInfo} object takes priority
* over the additional {@code BeanInfo} objects.
* Array elements with higher indices take priority
* over the elements with lower indices.
*
* @return an array of {@code BeanInfo} objects,
* or {@code null} if there are no additional {@code BeanInfo} objects
*/
BeanInfo[] getAdditionalBeanInfo();
/**
* Returns an image that can be used to represent the bean in toolboxes or toolbars.
* <p>
* There are four possible types of icons:
* 16 x 16 color, 32 x 32 color, 16 x 16 mono, and 32 x 32 mono.
* If you implement a bean so that it supports a single icon,
* it is recommended to use 16 x 16 color.
* Another recommendation is to set a transparent background for the icons.
*
* @param iconKind the kind of icon requested
* @return an image object representing the requested icon,
* or {@code null} if no suitable icon is available
*
* @see #ICON_COLOR_16x16
* @see #ICON_COLOR_32x32
* @see #ICON_MONO_16x16
* @see #ICON_MONO_32x32
*/
Image getIcon(int iconKind);
/**
* Constant to indicate a 16 x 16 color icon.
*/
final static int ICON_COLOR_16x16 = 1;
/**
* Constant to indicate a 32 x 32 color icon.
*/
final static int ICON_COLOR_32x32 = 2;
/**
* Constant to indicate a 16 x 16 monochrome icon.
*/
final static int ICON_MONO_16x16 = 3;
/**
* Constant to indicate a 32 x 32 monochrome icon.
*/
final static int ICON_MONO_32x32 = 4;
}

View File

@@ -0,0 +1,626 @@
/*
* Copyright (c) 1996, 2015, 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.finder.ClassFinder;
import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.applet.AudioClip;
import java.awt.Image;
import java.beans.beancontext.BeanContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
/**
* This class provides some general purpose beans control methods.
*/
public class Beans {
/**
* <p>
* Instantiate a JavaBean.
* </p>
* @return a JavaBean
* @param cls the class-loader from which we should create
* the bean. If this is null, then the system
* class-loader is used.
* @param beanName the name of the bean within the class-loader.
* For example "sun.beanbox.foobah"
*
* @exception ClassNotFoundException if the class of a serialized
* object could not be found.
* @exception IOException if an I/O error occurs.
*/
public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException {
return Beans.instantiate(cls, beanName, null, null);
}
/**
* <p>
* Instantiate a JavaBean.
* </p>
* @return a JavaBean
*
* @param cls the class-loader from which we should create
* the bean. If this is null, then the system
* class-loader is used.
* @param beanName the name of the bean within the class-loader.
* For example "sun.beanbox.foobah"
* @param beanContext The BeanContext in which to nest the new bean
*
* @exception ClassNotFoundException if the class of a serialized
* object could not be found.
* @exception IOException if an I/O error occurs.
*/
public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException {
return Beans.instantiate(cls, beanName, beanContext, null);
}
/**
* Instantiate a bean.
* <p>
* The bean is created based on a name relative to a class-loader.
* This name should be a dot-separated name such as "a.b.c".
* <p>
* In Beans 1.0 the given name can indicate either a serialized object
* or a class. Other mechanisms may be added in the future. In
* beans 1.0 we first try to treat the beanName as a serialized object
* name then as a class name.
* <p>
* When using the beanName as a serialized object name we convert the
* given beanName to a resource pathname and add a trailing ".ser" suffix.
* We then try to load a serialized object from that resource.
* <p>
* For example, given a beanName of "x.y", Beans.instantiate would first
* try to read a serialized object from the resource "x/y.ser" and if
* that failed it would try to load the class "x.y" and create an
* instance of that class.
* <p>
* If the bean is a subtype of java.applet.Applet, then it is given
* some special initialization. First, it is supplied with a default
* AppletStub and AppletContext. Second, if it was instantiated from
* a classname the applet's "init" method is called. (If the bean was
* deserialized this step is skipped.)
* <p>
* Note that for beans which are applets, it is the caller's responsiblity
* to call "start" on the applet. For correct behaviour, this should be done
* after the applet has been added into a visible AWT container.
* <p>
* Note that applets created via beans.instantiate run in a slightly
* different environment than applets running inside browsers. In
* particular, bean applets have no access to "parameters", so they may
* wish to provide property get/set methods to set parameter values. We
* advise bean-applet developers to test their bean-applets against both
* the JDK appletviewer (for a reference browser environment) and the
* BDK BeanBox (for a reference bean container).
*
* @return a JavaBean
* @param cls the class-loader from which we should create
* the bean. If this is null, then the system
* class-loader is used.
* @param beanName the name of the bean within the class-loader.
* For example "sun.beanbox.foobah"
* @param beanContext The BeanContext in which to nest the new bean
* @param initializer The AppletInitializer for the new bean
*
* @exception ClassNotFoundException if the class of a serialized
* object could not be found.
* @exception IOException if an I/O error occurs.
*/
public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
throws IOException, ClassNotFoundException {
InputStream ins;
ObjectInputStream oins = null;
Object result = null;
boolean serialized = false;
IOException serex = null;
// If the given classloader is null, we check if an
// system classloader is available and (if so)
// use that instead.
// Note that calls on the system class loader will
// look in the bootstrap class loader first.
if (cls == null) {
try {
cls = ClassLoader.getSystemClassLoader();
} catch (SecurityException ex) {
// We're not allowed to access the system class loader.
// Drop through.
}
}
// Try to find a serialized object with this name
final String serName = beanName.replace('.','/').concat(".ser");
if (cls == null)
ins = ClassLoader.getSystemResourceAsStream(serName);
else
ins = cls.getResourceAsStream(serName);
if (ins != null) {
try {
if (cls == null) {
oins = new ObjectInputStream(ins);
} else {
oins = new ObjectInputStreamWithLoader(ins, cls);
}
result = oins.readObject();
serialized = true;
oins.close();
} catch (IOException ex) {
ins.close();
// Drop through and try opening the class. But remember
// the exception in case we can't find the class either.
serex = ex;
} catch (ClassNotFoundException ex) {
ins.close();
throw ex;
}
}
if (result == null) {
// No serialized object, try just instantiating the class
Class<?> cl;
try {
cl = ClassFinder.findClass(beanName, cls);
} catch (ClassNotFoundException ex) {
// There is no appropriate class. If we earlier tried to
// deserialize an object and got an IO exception, throw that,
// otherwise rethrow the ClassNotFoundException.
if (serex != null) {
throw serex;
}
throw ex;
}
if (!Modifier.isPublic(cl.getModifiers())) {
throw new ClassNotFoundException("" + cl + " : no public access");
}
/*
* Try to instantiate the class.
*/
try {
result = cl.newInstance();
} catch (Exception ex) {
// We have to remap the exception to one in our signature.
// But we pass extra information in the detail message.
throw new ClassNotFoundException("" + cl + " : " + ex, ex);
}
}
if (result != null) {
// Ok, if the result is an applet initialize it.
AppletStub stub = null;
if (result instanceof Applet) {
Applet applet = (Applet) result;
boolean needDummies = initializer == null;
if (needDummies) {
// Figure our the codebase and docbase URLs. We do this
// by locating the URL for a known resource, and then
// massaging the URL.
// First find the "resource name" corresponding to the bean
// itself. So a serialzied bean "a.b.c" would imply a
// resource name of "a/b/c.ser" and a classname of "x.y"
// would imply a resource name of "x/y.class".
final String resourceName;
if (serialized) {
// Serialized bean
resourceName = beanName.replace('.','/').concat(".ser");
} else {
// Regular class
resourceName = beanName.replace('.','/').concat(".class");
}
URL objectUrl = null;
URL codeBase = null;
URL docBase = null;
// Now get the URL correponding to the resource name.
if (cls == null) {
objectUrl = ClassLoader.getSystemResource(resourceName);
} else
objectUrl = cls.getResource(resourceName);
// If we found a URL, we try to locate the docbase by taking
// of the final path name component, and the code base by taking
// of the complete resourceName.
// So if we had a resourceName of "a/b/c.class" and we got an
// objectURL of "file://bert/classes/a/b/c.class" then we would
// want to set the codebase to "file://bert/classes/" and the
// docbase to "file://bert/classes/a/b/"
if (objectUrl != null) {
String s = objectUrl.toExternalForm();
if (s.endsWith(resourceName)) {
int ix = s.length() - resourceName.length();
codeBase = new URL(s.substring(0,ix));
docBase = codeBase;
ix = s.lastIndexOf('/');
if (ix >= 0) {
docBase = new URL(s.substring(0,ix+1));
}
}
}
// Setup a default context and stub.
BeansAppletContext context = new BeansAppletContext(applet);
stub = (AppletStub)new BeansAppletStub(applet, context, codeBase, docBase);
applet.setStub(stub);
} else {
initializer.initialize(applet, beanContext);
}
// now, if there is a BeanContext, add the bean, if applicable.
if (beanContext != null) {
unsafeBeanContextAdd(beanContext, result);
}
// If it was deserialized then it was already init-ed.
// Otherwise we need to initialize it.
if (!serialized) {
// We need to set a reasonable initial size, as many
// applets are unhappy if they are started without
// having been explicitly sized.
applet.setSize(100,100);
applet.init();
}
if (needDummies) {
((BeansAppletStub)stub).active = true;
} else initializer.activate(applet);
} else if (beanContext != null) unsafeBeanContextAdd(beanContext, result);
}
return result;
}
@SuppressWarnings("unchecked")
private static void unsafeBeanContextAdd(BeanContext beanContext, Object res) {
beanContext.add(res);
}
/**
* From a given bean, obtain an object representing a specified
* type view of that source object.
* <p>
* The result may be the same object or a different object. If
* the requested target view isn't available then the given
* bean is returned.
* <p>
* This method is provided in Beans 1.0 as a hook to allow the
* addition of more flexible bean behaviour in the future.
*
* @return an object representing a specified type view of the
* source object
* @param bean Object from which we want to obtain a view.
* @param targetType The type of view we'd like to get.
*
*/
public static Object getInstanceOf(Object bean, Class<?> targetType) {
return bean;
}
/**
* Check if a bean can be viewed as a given target type.
* The result will be true if the Beans.getInstanceof method
* can be used on the given bean to obtain an object that
* represents the specified targetType type view.
*
* @param bean Bean from which we want to obtain a view.
* @param targetType The type of view we'd like to get.
* @return "true" if the given bean supports the given targetType.
*
*/
public static boolean isInstanceOf(Object bean, Class<?> targetType) {
return Introspector.isSubclass(bean.getClass(), targetType);
}
/**
* Test if we are in design-mode.
*
* @return True if we are running in an application construction
* environment.
*
* @see DesignMode
*/
public static boolean isDesignTime() {
return ThreadGroupContext.getContext().isDesignTime();
}
/**
* Determines whether beans can assume a GUI is available.
*
* @return True if we are running in an environment where beans
* can assume that an interactive GUI is available, so they
* can pop up dialog boxes, etc. This will normally return
* true in a windowing environment, and will normally return
* false in a server environment or if an application is
* running as part of a batch job.
*
* @see Visibility
*
*/
public static boolean isGuiAvailable() {
return ThreadGroupContext.getContext().isGuiAvailable();
}
/**
* Used to indicate whether of not we are running in an application
* builder environment.
*
* <p>Note that this method is security checked
* and is not available to (for example) untrusted applets.
* More specifically, if there is a security manager,
* its <code>checkPropertiesAccess</code>
* method is called. This could result in a SecurityException.
*
* @param isDesignTime True if we're in an application builder tool.
* @exception SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow setting
* of system properties.
* @see SecurityManager#checkPropertiesAccess
*/
public static void setDesignTime(boolean isDesignTime)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
ThreadGroupContext.getContext().setDesignTime(isDesignTime);
}
/**
* Used to indicate whether of not we are running in an environment
* where GUI interaction is available.
*
* <p>Note that this method is security checked
* and is not available to (for example) untrusted applets.
* More specifically, if there is a security manager,
* its <code>checkPropertiesAccess</code>
* method is called. This could result in a SecurityException.
*
* @param isGuiAvailable True if GUI interaction is available.
* @exception SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow setting
* of system properties.
* @see SecurityManager#checkPropertiesAccess
*/
public static void setGuiAvailable(boolean isGuiAvailable)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
ThreadGroupContext.getContext().setGuiAvailable(isGuiAvailable);
}
}
/**
* This subclass of ObjectInputStream delegates loading of classes to
* an existing ClassLoader.
*/
class ObjectInputStreamWithLoader extends ObjectInputStream
{
private ClassLoader loader;
/**
* Loader must be non-null;
*/
public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
throws IOException, StreamCorruptedException {
super(in);
if (loader == null) {
throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
}
this.loader = loader;
}
/**
* Use the given ClassLoader rather than using the system class
*/
@SuppressWarnings("rawtypes")
protected Class resolveClass(ObjectStreamClass classDesc)
throws IOException, ClassNotFoundException {
String cname = classDesc.getName();
return ClassFinder.resolveClass(cname, this.loader);
}
}
/**
* Package private support class. This provides a default AppletContext
* for beans which are applets.
*/
class BeansAppletContext implements AppletContext {
Applet target;
Hashtable<URL,Object> imageCache = new Hashtable<>();
BeansAppletContext(Applet target) {
this.target = target;
}
public AudioClip getAudioClip(URL url) {
// We don't currently support audio clips in the Beans.instantiate
// applet context, unless by some luck there exists a URL content
// class that can generate an AudioClip from the audio URL.
try {
return (AudioClip) url.getContent();
} catch (Exception ex) {
return null;
}
}
public synchronized Image getImage(URL url) {
Object o = imageCache.get(url);
if (o != null) {
return (Image)o;
}
try {
o = url.getContent();
if (o == null) {
return null;
}
if (o instanceof Image) {
imageCache.put(url, o);
return (Image) o;
}
// Otherwise it must be an ImageProducer.
Image img = target.createImage((java.awt.image.ImageProducer)o);
imageCache.put(url, img);
return img;
} catch (Exception ex) {
return null;
}
}
public Applet getApplet(String name) {
return null;
}
public Enumeration<Applet> getApplets() {
Vector<Applet> applets = new Vector<>();
applets.addElement(target);
return applets.elements();
}
public void showDocument(URL url) {
// We do nothing.
}
public void showDocument(URL url, String target) {
// We do nothing.
}
public void showStatus(String status) {
// We do nothing.
}
public void setStream(String key, InputStream stream)throws IOException{
// We do nothing.
}
public InputStream getStream(String key){
// We do nothing.
return null;
}
public Iterator<String> getStreamKeys(){
// We do nothing.
return null;
}
}
/**
* Package private support class. This provides an AppletStub
* for beans which are applets.
*/
class BeansAppletStub implements AppletStub {
transient boolean active;
transient Applet target;
transient AppletContext context;
transient URL codeBase;
transient URL docBase;
BeansAppletStub(Applet target,
AppletContext context, URL codeBase,
URL docBase) {
this.target = target;
this.context = context;
this.codeBase = codeBase;
this.docBase = docBase;
}
public boolean isActive() {
return active;
}
public URL getDocumentBase() {
// use the root directory of the applet's class-loader
return docBase;
}
public URL getCodeBase() {
// use the directory where we found the class or serialized object.
return codeBase;
}
public String getParameter(String name) {
return null;
}
public AppletContext getAppletContext() {
return context;
}
public void appletResize(int width, int height) {
// we do nothing.
}
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2012, 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 java.util.ArrayList;
import java.util.Collections;
import java.util.EventListener;
import java.util.EventListenerProxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* This is an abstract class that provides base functionality
* for the {@link PropertyChangeSupport PropertyChangeSupport} class
* and the {@link VetoableChangeSupport VetoableChangeSupport} class.
*
* @see PropertyChangeListenerMap
* @see VetoableChangeListenerMap
*
* @author Sergey A. Malenkov
*/
abstract class ChangeListenerMap<L extends EventListener> {
private Map<String, L[]> map;
/**
* Creates an array of listeners.
* This method can be optimized by using
* the same instance of the empty array
* when {@code length} is equal to {@code 0}.
*
* @param length the array length
* @return an array with specified length
*/
protected abstract L[] newArray(int length);
/**
* Creates a proxy listener for the specified property.
*
* @param name the name of the property to listen on
* @param listener the listener to process events
* @return a proxy listener
*/
protected abstract L newProxy(String name, L listener);
/**
* Adds a listener to the list of listeners for the specified property.
* This listener is called as many times as it was added.
*
* @param name the name of the property to listen on
* @param listener the listener to process events
*/
public final synchronized void add(String name, L listener) {
if (this.map == null) {
this.map = new HashMap<>();
}
L[] array = this.map.get(name);
int size = (array != null)
? array.length
: 0;
L[] clone = newArray(size + 1);
clone[size] = listener;
if (array != null) {
System.arraycopy(array, 0, clone, 0, size);
}
this.map.put(name, clone);
}
/**
* Removes a listener from the list of listeners for the specified property.
* If the listener was added more than once to the same event source,
* this listener will be notified one less time after being removed.
*
* @param name the name of the property to listen on
* @param listener the listener to process events
*/
public final synchronized void remove(String name, L listener) {
if (this.map != null) {
L[] array = this.map.get(name);
if (array != null) {
for (int i = 0; i < array.length; i++) {
if (listener.equals(array[i])) {
int size = array.length - 1;
if (size > 0) {
L[] clone = newArray(size);
System.arraycopy(array, 0, clone, 0, i);
System.arraycopy(array, i + 1, clone, i, size - i);
this.map.put(name, clone);
}
else {
this.map.remove(name);
if (this.map.isEmpty()) {
this.map = null;
}
}
break;
}
}
}
}
}
/**
* Returns the list of listeners for the specified property.
*
* @param name the name of the property
* @return the corresponding list of listeners
*/
public final synchronized L[] get(String name) {
return (this.map != null)
? this.map.get(name)
: null;
}
/**
* Sets new list of listeners for the specified property.
*
* @param name the name of the property
* @param listeners new list of listeners
*/
public final void set(String name, L[] listeners) {
if (listeners != null) {
if (this.map == null) {
this.map = new HashMap<>();
}
this.map.put(name, listeners);
}
else if (this.map != null) {
this.map.remove(name);
if (this.map.isEmpty()) {
this.map = null;
}
}
}
/**
* Returns all listeners in the map.
*
* @return an array of all listeners
*/
public final synchronized L[] getListeners() {
if (this.map == null) {
return newArray(0);
}
List<L> list = new ArrayList<>();
L[] listeners = this.map.get(null);
if (listeners != null) {
for (L listener : listeners) {
list.add(listener);
}
}
for (Entry<String, L[]> entry : this.map.entrySet()) {
String name = entry.getKey();
if (name != null) {
for (L listener : entry.getValue()) {
list.add(newProxy(name, listener));
}
}
}
return list.toArray(newArray(list.size()));
}
/**
* Returns listeners that have been associated with the named property.
*
* @param name the name of the property
* @return an array of listeners for the named property
*/
public final L[] getListeners(String name) {
if (name != null) {
L[] listeners = get(name);
if (listeners != null) {
return listeners.clone();
}
}
return newArray(0);
}
/**
* Indicates whether the map contains
* at least one listener to be notified.
*
* @param name the name of the property
* @return {@code true} if at least one listener exists or
* {@code false} otherwise
*/
public final synchronized boolean hasListeners(String name) {
if (this.map == null) {
return false;
}
L[] array = this.map.get(null);
return (array != null) || ((name != null) && (null != this.map.get(name)));
}
/**
* Returns a set of entries from the map.
* Each entry is a pair consisted of the property name
* and the corresponding list of listeners.
*
* @return a set of entries from the map
*/
public final Set<Entry<String, L[]>> getEntries() {
return (this.map != null)
? this.map.entrySet()
: Collections.<Entry<String, L[]>>emptySet();
}
/**
* Extracts a real listener from the proxy listener.
* It is necessary because default proxy class is not serializable.
*
* @return a real listener
*/
public abstract L extract(L listener);
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2006, 2013, 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 java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
<p>An annotation on a constructor that shows how the parameters of
that constructor correspond to the constructed object's getter
methods. For example:
<blockquote>
<pre>
public class Point {
&#64;ConstructorProperties({"x", "y"})
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
private final int x, y;
}
</pre>
</blockquote>
The annotation shows that the first parameter of the constructor
can be retrieved with the {@code getX()} method and the second with
the {@code getY()} method. Since parameter names are not in
general available at runtime, without the annotation there would be
no way to know whether the parameters correspond to {@code getX()}
and {@code getY()} or the other way around.
@since 1.6
*/
@Documented @Target(CONSTRUCTOR) @Retention(RUNTIME)
public @interface ConstructorProperties {
/**
<p>The getter names.</p>
@return the getter names corresponding to the parameters in the
annotated constructor.
*/
String[] value();
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 1996, 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;
/**
* A customizer class provides a complete custom GUI for customizing
* a target Java Bean.
* <P>
* Each customizer should inherit from the java.awt.Component class so
* it can be instantiated inside an AWT dialog or panel.
* <P>
* Each customizer should have a null constructor.
*/
public interface Customizer {
/**
* Set the object to be customized. This method should be called only
* once, before the Customizer has been added to any parent AWT container.
* @param bean The object to be customized.
*/
void setObject(Object bean);
/**
* Register a listener for the PropertyChange event. The customizer
* should fire a PropertyChange event whenever it changes the target
* bean in a way that might require the displayed properties to be
* refreshed.
*
* @param listener An object to be invoked when a PropertyChange
* event is fired.
*/
void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a listener for the PropertyChange event.
*
* @param listener The PropertyChange listener to be removed.
*/
void removePropertyChangeListener(PropertyChangeListener listener);
}

View File

@@ -0,0 +1,420 @@
/*
* Copyright (c) 2000, 2013, 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 java.util.*;
import java.lang.reflect.*;
import java.util.Objects;
import sun.reflect.misc.*;
/**
* The <code>DefaultPersistenceDelegate</code> is a concrete implementation of
* the abstract <code>PersistenceDelegate</code> class and
* is the delegate used by default for classes about
* which no information is available. The <code>DefaultPersistenceDelegate</code>
* provides, version resilient, public API-based persistence for
* classes that follow the JavaBeans&trade; conventions without any class specific
* configuration.
* <p>
* The key assumptions are that the class has a nullary constructor
* and that its state is accurately represented by matching pairs
* of "setter" and "getter" methods in the order they are returned
* by the Introspector.
* In addition to providing code-free persistence for JavaBeans,
* the <code>DefaultPersistenceDelegate</code> provides a convenient means
* to effect persistent storage for classes that have a constructor
* that, while not nullary, simply requires some property values
* as arguments.
*
* @see #DefaultPersistenceDelegate(String[])
* @see java.beans.Introspector
*
* @since 1.4
*
* @author Philip Milne
*/
public class DefaultPersistenceDelegate extends PersistenceDelegate {
private static final String[] EMPTY = {};
private final String[] constructor;
private Boolean definesEquals;
/**
* Creates a persistence delegate for a class with a nullary constructor.
*
* @see #DefaultPersistenceDelegate(java.lang.String[])
*/
public DefaultPersistenceDelegate() {
this.constructor = EMPTY;
}
/**
* Creates a default persistence delegate for a class with a
* constructor whose arguments are the values of the property
* names as specified by <code>constructorPropertyNames</code>.
* The constructor arguments are created by
* evaluating the property names in the order they are supplied.
* To use this class to specify a single preferred constructor for use
* in the serialization of a particular type, we state the
* names of the properties that make up the constructor's
* arguments. For example, the <code>Font</code> class which
* does not define a nullary constructor can be handled
* with the following persistence delegate:
*
* <pre>
* new DefaultPersistenceDelegate(new String[]{"name", "style", "size"});
* </pre>
*
* @param constructorPropertyNames The property names for the arguments of this constructor.
*
* @see #instantiate
*/
public DefaultPersistenceDelegate(String[] constructorPropertyNames) {
this.constructor = (constructorPropertyNames == null) ? EMPTY : constructorPropertyNames.clone();
}
private static boolean definesEquals(Class<?> type) {
try {
return type == type.getMethod("equals", Object.class).getDeclaringClass();
}
catch(NoSuchMethodException e) {
return false;
}
}
private boolean definesEquals(Object instance) {
if (definesEquals != null) {
return (definesEquals == Boolean.TRUE);
}
else {
boolean result = definesEquals(instance.getClass());
definesEquals = result ? Boolean.TRUE : Boolean.FALSE;
return result;
}
}
/**
* If the number of arguments in the specified constructor is non-zero and
* the class of <code>oldInstance</code> explicitly declares an "equals" method
* this method returns the value of <code>oldInstance.equals(newInstance)</code>.
* Otherwise, this method uses the superclass's definition which returns true if the
* classes of the two instances are equal.
*
* @param oldInstance The instance to be copied.
* @param newInstance The instance that is to be modified.
* @return True if an equivalent copy of <code>newInstance</code> may be
* created by applying a series of mutations to <code>oldInstance</code>.
*
* @see #DefaultPersistenceDelegate(String[])
*/
protected boolean mutatesTo(Object oldInstance, Object newInstance) {
// Assume the instance is either mutable or a singleton
// if it has a nullary constructor.
return (constructor.length == 0) || !definesEquals(oldInstance) ?
super.mutatesTo(oldInstance, newInstance) :
oldInstance.equals(newInstance);
}
/**
* This default implementation of the <code>instantiate</code> method returns
* an expression containing the predefined method name "new" which denotes a
* call to a constructor with the arguments as specified in
* the <code>DefaultPersistenceDelegate</code>'s constructor.
*
* @param oldInstance The instance to be instantiated.
* @param out The code output stream.
* @return An expression whose value is <code>oldInstance</code>.
*
* @throws NullPointerException if {@code out} is {@code null}
* and this value is used in the method
*
* @see #DefaultPersistenceDelegate(String[])
*/
protected Expression instantiate(Object oldInstance, Encoder out) {
int nArgs = constructor.length;
Class<?> type = oldInstance.getClass();
Object[] constructorArgs = new Object[nArgs];
for(int i = 0; i < nArgs; i++) {
try {
Method method = findMethod(type, this.constructor[i]);
constructorArgs[i] = MethodUtil.invoke(method, oldInstance, new Object[0]);
}
catch (Exception e) {
out.getExceptionListener().exceptionThrown(e);
}
}
return new Expression(oldInstance, oldInstance.getClass(), "new", constructorArgs);
}
private Method findMethod(Class<?> type, String property) {
if (property == null) {
throw new IllegalArgumentException("Property name is null");
}
PropertyDescriptor pd = getPropertyDescriptor(type, property);
if (pd == null) {
throw new IllegalStateException("Could not find property by the name " + property);
}
Method method = pd.getReadMethod();
if (method == null) {
throw new IllegalStateException("Could not find getter for the property " + property);
}
return method;
}
private void doProperty(Class<?> type, PropertyDescriptor pd, Object oldInstance, Object newInstance, Encoder out) throws Exception {
Method getter = pd.getReadMethod();
Method setter = pd.getWriteMethod();
if (getter != null && setter != null) {
Expression oldGetExp = new Expression(oldInstance, getter.getName(), new Object[]{});
Expression newGetExp = new Expression(newInstance, getter.getName(), new Object[]{});
Object oldValue = oldGetExp.getValue();
Object newValue = newGetExp.getValue();
out.writeExpression(oldGetExp);
if (!Objects.equals(newValue, out.get(oldValue))) {
// Search for a static constant with this value;
Object e = (Object[])pd.getValue("enumerationValues");
if (e instanceof Object[] && Array.getLength(e) % 3 == 0) {
Object[] a = (Object[])e;
for(int i = 0; i < a.length; i = i + 3) {
try {
Field f = type.getField((String)a[i]);
if (f.get(null).equals(oldValue)) {
out.remove(oldValue);
out.writeExpression(new Expression(oldValue, f, "get", new Object[]{null}));
}
}
catch (Exception ex) {}
}
}
invokeStatement(oldInstance, setter.getName(), new Object[]{oldValue}, out);
}
}
}
static void invokeStatement(Object instance, String methodName, Object[] args, Encoder out) {
out.writeStatement(new Statement(instance, methodName, args));
}
// Write out the properties of this instance.
private void initBean(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
for (Field field : type.getFields()) {
if (!ReflectUtil.isPackageAccessible(field.getDeclaringClass())) {
continue;
}
int mod = field.getModifiers();
if (Modifier.isFinal(mod) || Modifier.isStatic(mod) || Modifier.isTransient(mod)) {
continue;
}
try {
Expression oldGetExp = new Expression(field, "get", new Object[] { oldInstance });
Expression newGetExp = new Expression(field, "get", new Object[] { newInstance });
Object oldValue = oldGetExp.getValue();
Object newValue = newGetExp.getValue();
out.writeExpression(oldGetExp);
if (!Objects.equals(newValue, out.get(oldValue))) {
out.writeStatement(new Statement(field, "set", new Object[] { oldInstance, oldValue }));
}
}
catch (Exception exception) {
out.getExceptionListener().exceptionThrown(exception);
}
}
BeanInfo info;
try {
info = Introspector.getBeanInfo(type);
} catch (IntrospectionException exception) {
return;
}
// Properties
for (PropertyDescriptor d : info.getPropertyDescriptors()) {
if (d.isTransient()) {
continue;
}
try {
doProperty(type, d, oldInstance, newInstance, out);
}
catch (Exception e) {
out.getExceptionListener().exceptionThrown(e);
}
}
// Listeners
/*
Pending(milne). There is a general problem with the archival of
listeners which is unresolved as of 1.4. Many of the methods
which install one object inside another (typically "add" methods
or setters) automatically install a listener on the "child" object
so that its "parent" may respond to changes that are made to it.
For example the JTable:setModel() method automatically adds a
TableModelListener (the JTable itself in this case) to the supplied
table model.
We do not need to explicitly add these listeners to the model in an
archive as they will be added automatically by, in the above case,
the JTable's "setModel" method. In some cases, we must specifically
avoid trying to do this since the listener may be an inner class
that cannot be instantiated using public API.
No general mechanism currently
exists for differentiating between these kind of listeners and
those which were added explicitly by the user. A mechanism must
be created to provide a general means to differentiate these
special cases so as to provide reliable persistence of listeners
for the general case.
*/
if (!java.awt.Component.class.isAssignableFrom(type)) {
return; // Just handle the listeners of Components for now.
}
for (EventSetDescriptor d : info.getEventSetDescriptors()) {
if (d.isTransient()) {
continue;
}
Class<?> listenerType = d.getListenerType();
// The ComponentListener is added automatically, when
// Contatiner:add is called on the parent.
if (listenerType == java.awt.event.ComponentListener.class) {
continue;
}
// JMenuItems have a change listener added to them in
// their "add" methods to enable accessibility support -
// see the add method in JMenuItem for details. We cannot
// instantiate this instance as it is a private inner class
// and do not need to do this anyway since it will be created
// and installed by the "add" method. Special case this for now,
// ignoring all change listeners on JMenuItems.
if (listenerType == javax.swing.event.ChangeListener.class &&
type == javax.swing.JMenuItem.class) {
continue;
}
EventListener[] oldL = new EventListener[0];
EventListener[] newL = new EventListener[0];
try {
Method m = d.getGetListenerMethod();
oldL = (EventListener[])MethodUtil.invoke(m, oldInstance, new Object[]{});
newL = (EventListener[])MethodUtil.invoke(m, newInstance, new Object[]{});
}
catch (Exception e2) {
try {
Method m = type.getMethod("getListeners", new Class<?>[]{Class.class});
oldL = (EventListener[])MethodUtil.invoke(m, oldInstance, new Object[]{listenerType});
newL = (EventListener[])MethodUtil.invoke(m, newInstance, new Object[]{listenerType});
}
catch (Exception e3) {
return;
}
}
// Asssume the listeners are in the same order and that there are no gaps.
// Eventually, this may need to do true differencing.
String addListenerMethodName = d.getAddListenerMethod().getName();
for (int i = newL.length; i < oldL.length; i++) {
// System.out.println("Adding listener: " + addListenerMethodName + oldL[i]);
invokeStatement(oldInstance, addListenerMethodName, new Object[]{oldL[i]}, out);
}
String removeListenerMethodName = d.getRemoveListenerMethod().getName();
for (int i = oldL.length; i < newL.length; i++) {
invokeStatement(oldInstance, removeListenerMethodName, new Object[]{newL[i]}, out);
}
}
}
/**
* This default implementation of the <code>initialize</code> method assumes
* all state held in objects of this type is exposed via the
* matching pairs of "setter" and "getter" methods in the order
* they are returned by the Introspector. If a property descriptor
* defines a "transient" attribute with a value equal to
* <code>Boolean.TRUE</code> the property is ignored by this
* default implementation. Note that this use of the word
* "transient" is quite independent of the field modifier
* that is used by the <code>ObjectOutputStream</code>.
* <p>
* For each non-transient property, an expression is created
* in which the nullary "getter" method is applied
* to the <code>oldInstance</code>. The value of this
* expression is the value of the property in the instance that is
* being serialized. If the value of this expression
* in the cloned environment <code>mutatesTo</code> the
* target value, the new value is initialized to make it
* equivalent to the old value. In this case, because
* the property value has not changed there is no need to
* call the corresponding "setter" method and no statement
* is emitted. If not however, the expression for this value
* is replaced with another expression (normally a constructor)
* and the corresponding "setter" method is called to install
* the new property value in the object. This scheme removes
* default information from the output produced by streams
* using this delegate.
* <p>
* In passing these statements to the output stream, where they
* will be executed, side effects are made to the <code>newInstance</code>.
* In most cases this allows the problem of properties
* whose values depend on each other to actually help the
* serialization process by making the number of statements
* that need to be written to the output smaller. In general,
* the problem of handling interdependent properties is reduced to
* that of finding an order for the properties in
* a class such that no property value depends on the value of
* a subsequent property.
*
* @param type the type of the instances
* @param oldInstance The instance to be copied.
* @param newInstance The instance that is to be modified.
* @param out The stream to which any initialization statements should be written.
*
* @throws NullPointerException if {@code out} is {@code null}
*
* @see java.beans.Introspector#getBeanInfo
* @see java.beans.PropertyDescriptor
*/
protected void initialize(Class<?> type,
Object oldInstance, Object newInstance,
Encoder out)
{
// System.out.println("DefulatPD:initialize" + type);
super.initialize(type, oldInstance, newInstance, out);
if (oldInstance.getClass() == type) { // !type.isInterface()) {
initBean(type, oldInstance, newInstance, out);
}
}
private static PropertyDescriptor getPropertyDescriptor(Class<?> type, String property) {
try {
for (PropertyDescriptor pd : Introspector.getBeanInfo(type).getPropertyDescriptors()) {
if (property.equals(pd.getName()))
return pd;
}
} catch (IntrospectionException exception) {
}
return null;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 1997, 2011, 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;
/**
* <p>
* This interface is intended to be implemented by, or delegated from, instances
* of java.beans.beancontext.BeanContext, in order to propagate to its nested hierarchy
* of java.beans.beancontext.BeanContextChild instances, the current "designTime" property.
* <p>
* The JavaBeans&trade; specification defines the notion of design time as is a
* mode in which JavaBeans instances should function during their composition
* and customization in a interactive design, composition or construction tool,
* as opposed to runtime when the JavaBean is part of an applet, application,
* or other live Java executable abstraction.
*
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.beancontext.BeanContext
* @see java.beans.beancontext.BeanContextChild
* @see java.beans.beancontext.BeanContextMembershipListener
* @see java.beans.PropertyChangeEvent
*/
public interface DesignMode {
/**
* The standard value of the propertyName as fired from a BeanContext or
* other source of PropertyChangeEvents.
*/
static String PROPERTYNAME = "designTime";
/**
* Sets the "value" of the "designTime" property.
* <p>
* If the implementing object is an instance of java.beans.beancontext.BeanContext,
* or a subinterface thereof, then that BeanContext should fire a
* PropertyChangeEvent, to its registered BeanContextMembershipListeners, with
* parameters:
* <ul>
* <li><code>propertyName</code> - <code>java.beans.DesignMode.PROPERTYNAME</code>
* <li><code>oldValue</code> - previous value of "designTime"
* <li><code>newValue</code> - current value of "designTime"
* </ul>
* Note it is illegal for a BeanContextChild to invoke this method
* associated with a BeanContext that it is nested within.
*
* @param designTime the current "value" of the "designTime" property
* @see java.beans.beancontext.BeanContext
* @see java.beans.beancontext.BeanContextMembershipListener
* @see java.beans.PropertyChangeEvent
*/
void setDesignTime(boolean designTime);
/**
* A value of true denotes that JavaBeans should behave in design time
* mode, a value of false denotes runtime behavior.
*
* @return the current "value" of the "designTime" property.
*/
boolean isDesignTime();
}

View File

@@ -0,0 +1,351 @@
/*
* Copyright (c) 2000, 2011, 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.finder.PersistenceDelegateFinder;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
/**
* An <code>Encoder</code> is a class which can be used to create
* files or streams that encode the state of a collection of
* JavaBeans in terms of their public APIs. The <code>Encoder</code>,
* in conjunction with its persistence delegates, is responsible for
* breaking the object graph down into a series of <code>Statements</code>s
* and <code>Expression</code>s which can be used to create it.
* A subclass typically provides a syntax for these expressions
* using some human readable form - like Java source code or XML.
*
* @since 1.4
*
* @author Philip Milne
*/
public class Encoder {
private final PersistenceDelegateFinder finder = new PersistenceDelegateFinder();
private Map<Object, Expression> bindings = new IdentityHashMap<>();
private ExceptionListener exceptionListener;
boolean executeStatements = true;
private Map<Object, Object> attributes;
/**
* Write the specified object to the output stream.
* The serialized form will denote a series of
* expressions, the combined effect of which will create
* an equivalent object when the input stream is read.
* By default, the object is assumed to be a <em>JavaBean</em>
* with a nullary constructor, whose state is defined by
* the matching pairs of "setter" and "getter" methods
* returned by the Introspector.
*
* @param o The object to be written to the stream.
*
* @see XMLDecoder#readObject
*/
protected void writeObject(Object o) {
if (o == this) {
return;
}
PersistenceDelegate info = getPersistenceDelegate(o == null ? null : o.getClass());
info.writeObject(o, this);
}
/**
* Sets the exception handler for this stream to <code>exceptionListener</code>.
* The exception handler is notified when this stream catches recoverable
* exceptions.
*
* @param exceptionListener The exception handler for this stream;
* if <code>null</code> the default exception listener will be used.
*
* @see #getExceptionListener
*/
public void setExceptionListener(ExceptionListener exceptionListener) {
this.exceptionListener = exceptionListener;
}
/**
* Gets the exception handler for this stream.
*
* @return The exception handler for this stream;
* Will return the default exception listener if this has not explicitly been set.
*
* @see #setExceptionListener
*/
public ExceptionListener getExceptionListener() {
return (exceptionListener != null) ? exceptionListener : Statement.defaultExceptionListener;
}
Object getValue(Expression exp) {
try {
return (exp == null) ? null : exp.getValue();
}
catch (Exception e) {
getExceptionListener().exceptionThrown(e);
throw new RuntimeException("failed to evaluate: " + exp.toString());
}
}
/**
* Returns the persistence delegate for the given type.
* The persistence delegate is calculated by applying
* the following rules in order:
* <ol>
* <li>
* If a persistence delegate is associated with the given type
* by using the {@link #setPersistenceDelegate} method
* it is returned.
* <li>
* A persistence delegate is then looked up by the name
* composed of the the fully qualified name of the given type
* and the "PersistenceDelegate" postfix.
* For example, a persistence delegate for the {@code Bean} class
* should be named {@code BeanPersistenceDelegate}
* and located in the same package.
* <pre>
* public class Bean { ... }
* public class BeanPersistenceDelegate { ... }</pre>
* The instance of the {@code BeanPersistenceDelegate} class
* is returned for the {@code Bean} class.
* <li>
* If the type is {@code null},
* a shared internal persistence delegate is returned
* that encodes {@code null} value.
* <li>
* If the type is a {@code enum} declaration,
* a shared internal persistence delegate is returned
* that encodes constants of this enumeration
* by their names.
* <li>
* If the type is a primitive type or the corresponding wrapper,
* a shared internal persistence delegate is returned
* that encodes values of the given type.
* <li>
* If the type is an array,
* a shared internal persistence delegate is returned
* that encodes an array of the appropriate type and length,
* and each of its elements as if they are properties.
* <li>
* If the type is a proxy,
* a shared internal persistence delegate is returned
* that encodes a proxy instance by using
* the {@link java.lang.reflect.Proxy#newProxyInstance} method.
* <li>
* If the {@link BeanInfo} for this type has a {@link BeanDescriptor}
* which defined a "persistenceDelegate" attribute,
* the value of this named attribute is returned.
* <li>
* In all other cases the default persistence delegate is returned.
* The default persistence delegate assumes the type is a <em>JavaBean</em>,
* implying that it has a default constructor and that its state
* may be characterized by the matching pairs of "setter" and "getter"
* methods returned by the {@link Introspector} class.
* The default constructor is the constructor with the greatest number
* of parameters that has the {@link ConstructorProperties} annotation.
* If none of the constructors has the {@code ConstructorProperties} annotation,
* then the nullary constructor (constructor with no parameters) will be used.
* For example, in the following code fragment, the nullary constructor
* for the {@code Foo} class will be used,
* while the two-parameter constructor
* for the {@code Bar} class will be used.
* <pre>
* public class Foo {
* public Foo() { ... }
* public Foo(int x) { ... }
* }
* public class Bar {
* public Bar() { ... }
* &#64;ConstructorProperties({"x"})
* public Bar(int x) { ... }
* &#64;ConstructorProperties({"x", "y"})
* public Bar(int x, int y) { ... }
* }</pre>
* </ol>
*
* @param type the class of the objects
* @return the persistence delegate for the given type
*
* @see #setPersistenceDelegate
* @see java.beans.Introspector#getBeanInfo
* @see java.beans.BeanInfo#getBeanDescriptor
*/
public PersistenceDelegate getPersistenceDelegate(Class<?> type) {
PersistenceDelegate pd = this.finder.find(type);
if (pd == null) {
pd = MetaData.getPersistenceDelegate(type);
if (pd != null) {
this.finder.register(type, pd);
}
}
return pd;
}
/**
* Associates the specified persistence delegate with the given type.
*
* @param type the class of objects that the specified persistence delegate applies to
* @param delegate the persistence delegate for instances of the given type
*
* @see #getPersistenceDelegate
* @see java.beans.Introspector#getBeanInfo
* @see java.beans.BeanInfo#getBeanDescriptor
*/
public void setPersistenceDelegate(Class<?> type, PersistenceDelegate delegate) {
this.finder.register(type, delegate);
}
/**
* Removes the entry for this instance, returning the old entry.
*
* @param oldInstance The entry that should be removed.
* @return The entry that was removed.
*
* @see #get
*/
public Object remove(Object oldInstance) {
Expression exp = bindings.remove(oldInstance);
return getValue(exp);
}
/**
* Returns a tentative value for <code>oldInstance</code> in
* the environment created by this stream. A persistence
* delegate can use its <code>mutatesTo</code> method to
* determine whether this value may be initialized to
* form the equivalent object at the output or whether
* a new object must be instantiated afresh. If the
* stream has not yet seen this value, null is returned.
*
* @param oldInstance The instance to be looked up.
* @return The object, null if the object has not been seen before.
*/
public Object get(Object oldInstance) {
if (oldInstance == null || oldInstance == this ||
oldInstance.getClass() == String.class) {
return oldInstance;
}
Expression exp = bindings.get(oldInstance);
return getValue(exp);
}
private Object writeObject1(Object oldInstance) {
Object o = get(oldInstance);
if (o == null) {
writeObject(oldInstance);
o = get(oldInstance);
}
return o;
}
private Statement cloneStatement(Statement oldExp) {
Object oldTarget = oldExp.getTarget();
Object newTarget = writeObject1(oldTarget);
Object[] oldArgs = oldExp.getArguments();
Object[] newArgs = new Object[oldArgs.length];
for (int i = 0; i < oldArgs.length; i++) {
newArgs[i] = writeObject1(oldArgs[i]);
}
Statement newExp = Statement.class.equals(oldExp.getClass())
? new Statement(newTarget, oldExp.getMethodName(), newArgs)
: new Expression(newTarget, oldExp.getMethodName(), newArgs);
newExp.loader = oldExp.loader;
return newExp;
}
/**
* Writes statement <code>oldStm</code> to the stream.
* The <code>oldStm</code> should be written entirely
* in terms of the callers environment, i.e. the
* target and all arguments should be part of the
* object graph being written. These expressions
* represent a series of "what happened" expressions
* which tell the output stream how to produce an
* object graph like the original.
* <p>
* The implementation of this method will produce
* a second expression to represent the same expression in
* an environment that will exist when the stream is read.
* This is achieved simply by calling <code>writeObject</code>
* on the target and all the arguments and building a new
* expression with the results.
*
* @param oldStm The expression to be written to the stream.
*/
public void writeStatement(Statement oldStm) {
// System.out.println("writeStatement: " + oldExp);
Statement newStm = cloneStatement(oldStm);
if (oldStm.getTarget() != this && executeStatements) {
try {
newStm.execute();
} catch (Exception e) {
getExceptionListener().exceptionThrown(new Exception("Encoder: discarding statement "
+ newStm, e));
}
}
}
/**
* The implementation first checks to see if an
* expression with this value has already been written.
* If not, the expression is cloned, using
* the same procedure as <code>writeStatement</code>,
* and the value of this expression is reconciled
* with the value of the cloned expression
* by calling <code>writeObject</code>.
*
* @param oldExp The expression to be written to the stream.
*/
public void writeExpression(Expression oldExp) {
// System.out.println("Encoder::writeExpression: " + oldExp);
Object oldValue = getValue(oldExp);
if (get(oldValue) != null) {
return;
}
bindings.put(oldValue, (Expression)cloneStatement(oldExp));
writeObject(oldValue);
}
void clear() {
bindings.clear();
}
// Package private method for setting an attributes table for the encoder
void setAttribute(Object key, Object value) {
if (attributes == null) {
attributes = new HashMap<>();
}
attributes.put(key, value);
}
Object getAttribute(Object key) {
if (attributes == null) {
return null;
}
return attributes.get(key);
}
}

View File

@@ -0,0 +1,715 @@
/*
* Copyright (c) 2000, 2013, 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 java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.reflect.misc.MethodUtil;
import sun.reflect.misc.ReflectUtil;
/**
* The <code>EventHandler</code> class provides
* support for dynamically generating event listeners whose methods
* execute a simple statement involving an incoming event object
* and a target object.
* <p>
* The <code>EventHandler</code> class is intended to be used by interactive tools, such as
* application builders, that allow developers to make connections between
* beans. Typically connections are made from a user interface bean
* (the event <em>source</em>)
* to an application logic bean (the <em>target</em>). The most effective
* connections of this kind isolate the application logic from the user
* interface. For example, the <code>EventHandler</code> for a
* connection from a <code>JCheckBox</code> to a method
* that accepts a boolean value can deal with extracting the state
* of the check box and passing it directly to the method so that
* the method is isolated from the user interface layer.
* <p>
* Inner classes are another, more general way to handle events from
* user interfaces. The <code>EventHandler</code> class
* handles only a subset of what is possible using inner
* classes. However, <code>EventHandler</code> works better
* with the long-term persistence scheme than inner classes.
* Also, using <code>EventHandler</code> in large applications in
* which the same interface is implemented many times can
* reduce the disk and memory footprint of the application.
* <p>
* The reason that listeners created with <code>EventHandler</code>
* have such a small
* footprint is that the <code>Proxy</code> class, on which
* the <code>EventHandler</code> relies, shares implementations
* of identical
* interfaces. For example, if you use
* the <code>EventHandler</code> <code>create</code> methods to make
* all the <code>ActionListener</code>s in an application,
* all the action listeners will be instances of a single class
* (one created by the <code>Proxy</code> class).
* In general, listeners based on
* the <code>Proxy</code> class require one listener class
* to be created per <em>listener type</em> (interface),
* whereas the inner class
* approach requires one class to be created per <em>listener</em>
* (object that implements the interface).
*
* <p>
* You don't generally deal directly with <code>EventHandler</code>
* instances.
* Instead, you use one of the <code>EventHandler</code>
* <code>create</code> methods to create
* an object that implements a given listener interface.
* This listener object uses an <code>EventHandler</code> object
* behind the scenes to encapsulate information about the
* event, the object to be sent a message when the event occurs,
* the message (method) to be sent, and any argument
* to the method.
* The following section gives examples of how to create listener
* objects using the <code>create</code> methods.
*
* <h2>Examples of Using EventHandler</h2>
*
* The simplest use of <code>EventHandler</code> is to install
* a listener that calls a method on the target object with no arguments.
* In the following example we create an <code>ActionListener</code>
* that invokes the <code>toFront</code> method on an instance
* of <code>javax.swing.JFrame</code>.
*
* <blockquote>
*<pre>
*myButton.addActionListener(
* (ActionListener)EventHandler.create(ActionListener.class, frame, "toFront"));
*</pre>
* </blockquote>
*
* When <code>myButton</code> is pressed, the statement
* <code>frame.toFront()</code> will be executed. One could get
* the same effect, with some additional compile-time type safety,
* by defining a new implementation of the <code>ActionListener</code>
* interface and adding an instance of it to the button:
*
* <blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*myButton.addActionListener(new ActionListener() {
* public void actionPerformed(ActionEvent e) {
* frame.toFront();
* }
*});
*</pre>
* </blockquote>
*
* The next simplest use of <code>EventHandler</code> is
* to extract a property value from the first argument
* of the method in the listener interface (typically an event object)
* and use it to set the value of a property in the target object.
* In the following example we create an <code>ActionListener</code> that
* sets the <code>nextFocusableComponent</code> property of the target
* (myButton) object to the value of the "source" property of the event.
*
* <blockquote>
*<pre>
*EventHandler.create(ActionListener.class, myButton, "nextFocusableComponent", "source")
*</pre>
* </blockquote>
*
* This would correspond to the following inner class implementation:
*
* <blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*new ActionListener() {
* public void actionPerformed(ActionEvent e) {
* myButton.setNextFocusableComponent((Component)e.getSource());
* }
*}
*</pre>
* </blockquote>
*
* It's also possible to create an <code>EventHandler</code> that
* just passes the incoming event object to the target's action.
* If the fourth <code>EventHandler.create</code> argument is
* an empty string, then the event is just passed along:
*
* <blockquote>
*<pre>
*EventHandler.create(ActionListener.class, target, "doActionEvent", "")
*</pre>
* </blockquote>
*
* This would correspond to the following inner class implementation:
*
* <blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*new ActionListener() {
* public void actionPerformed(ActionEvent e) {
* target.doActionEvent(e);
* }
*}
*</pre>
* </blockquote>
*
* Probably the most common use of <code>EventHandler</code>
* is to extract a property value from the
* <em>source</em> of the event object and set this value as
* the value of a property of the target object.
* In the following example we create an <code>ActionListener</code> that
* sets the "label" property of the target
* object to the value of the "text" property of the
* source (the value of the "source" property) of the event.
*
* <blockquote>
*<pre>
*EventHandler.create(ActionListener.class, myButton, "label", "source.text")
*</pre>
* </blockquote>
*
* This would correspond to the following inner class implementation:
*
* <blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*new ActionListener {
* public void actionPerformed(ActionEvent e) {
* myButton.setLabel(((JTextField)e.getSource()).getText());
* }
*}
*</pre>
* </blockquote>
*
* The event property may be "qualified" with an arbitrary number
* of property prefixes delimited with the "." character. The "qualifying"
* names that appear before the "." characters are taken as the names of
* properties that should be applied, left-most first, to
* the event object.
* <p>
* For example, the following action listener
*
* <blockquote>
*<pre>
*EventHandler.create(ActionListener.class, target, "a", "b.c.d")
*</pre>
* </blockquote>
*
* might be written as the following inner class
* (assuming all the properties had canonical getter methods and
* returned the appropriate types):
*
* <blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*new ActionListener {
* public void actionPerformed(ActionEvent e) {
* target.setA(e.getB().getC().isD());
* }
*}
*</pre>
* </blockquote>
* The target property may also be "qualified" with an arbitrary number
* of property prefixs delimited with the "." character. For example, the
* following action listener:
* <pre>
* EventHandler.create(ActionListener.class, target, "a.b", "c.d")
* </pre>
* might be written as the following inner class
* (assuming all the properties had canonical getter methods and
* returned the appropriate types):
* <pre>
* //Equivalent code using an inner class instead of EventHandler.
* new ActionListener {
* public void actionPerformed(ActionEvent e) {
* target.getA().setB(e.getC().isD());
* }
*}
*</pre>
* <p>
* As <code>EventHandler</code> ultimately relies on reflection to invoke
* a method we recommend against targeting an overloaded method. For example,
* if the target is an instance of the class <code>MyTarget</code> which is
* defined as:
* <pre>
* public class MyTarget {
* public void doIt(String);
* public void doIt(Object);
* }
* </pre>
* Then the method <code>doIt</code> is overloaded. EventHandler will invoke
* the method that is appropriate based on the source. If the source is
* null, then either method is appropriate and the one that is invoked is
* undefined. For that reason we recommend against targeting overloaded
* methods.
*
* @see java.lang.reflect.Proxy
* @see java.util.EventObject
*
* @since 1.4
*
* @author Mark Davidson
* @author Philip Milne
* @author Hans Muller
*
*/
public class EventHandler implements InvocationHandler {
private Object target;
private String action;
private final String eventPropertyName;
private final String listenerMethodName;
private final AccessControlContext acc = AccessController.getContext();
/**
* Creates a new <code>EventHandler</code> object;
* you generally use one of the <code>create</code> methods
* instead of invoking this constructor directly. Refer to
* {@link java.beans.EventHandler#create(Class, Object, String, String)
* the general version of create} for a complete description of
* the <code>eventPropertyName</code> and <code>listenerMethodName</code>
* parameter.
*
* @param target the object that will perform the action
* @param action the name of a (possibly qualified) property or method on
* the target
* @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
* @param listenerMethodName the name of the method in the listener interface that should trigger the action
*
* @throws NullPointerException if <code>target</code> is null
* @throws NullPointerException if <code>action</code> is null
*
* @see EventHandler
* @see #create(Class, Object, String, String, String)
* @see #getTarget
* @see #getAction
* @see #getEventPropertyName
* @see #getListenerMethodName
*/
@ConstructorProperties({"target", "action", "eventPropertyName", "listenerMethodName"})
public EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName) {
this.target = target;
this.action = action;
if (target == null) {
throw new NullPointerException("target must be non-null");
}
if (action == null) {
throw new NullPointerException("action must be non-null");
}
this.eventPropertyName = eventPropertyName;
this.listenerMethodName = listenerMethodName;
}
/**
* Returns the object to which this event handler will send a message.
*
* @return the target of this event handler
* @see #EventHandler(Object, String, String, String)
*/
public Object getTarget() {
return target;
}
/**
* Returns the name of the target's writable property
* that this event handler will set,
* or the name of the method that this event handler
* will invoke on the target.
*
* @return the action of this event handler
* @see #EventHandler(Object, String, String, String)
*/
public String getAction() {
return action;
}
/**
* Returns the property of the event that should be
* used in the action applied to the target.
*
* @return the property of the event
*
* @see #EventHandler(Object, String, String, String)
*/
public String getEventPropertyName() {
return eventPropertyName;
}
/**
* Returns the name of the method that will trigger the action.
* A return value of <code>null</code> signifies that all methods in the
* listener interface trigger the action.
*
* @return the name of the method that will trigger the action
*
* @see #EventHandler(Object, String, String, String)
*/
public String getListenerMethodName() {
return listenerMethodName;
}
private Object applyGetters(Object target, String getters) {
if (getters == null || getters.equals("")) {
return target;
}
int firstDot = getters.indexOf('.');
if (firstDot == -1) {
firstDot = getters.length();
}
String first = getters.substring(0, firstDot);
String rest = getters.substring(Math.min(firstDot + 1, getters.length()));
try {
Method getter = null;
if (target != null) {
getter = Statement.getMethod(target.getClass(),
"get" + NameGenerator.capitalize(first),
new Class<?>[]{});
if (getter == null) {
getter = Statement.getMethod(target.getClass(),
"is" + NameGenerator.capitalize(first),
new Class<?>[]{});
}
if (getter == null) {
getter = Statement.getMethod(target.getClass(), first, new Class<?>[]{});
}
}
if (getter == null) {
throw new RuntimeException("No method called: " + first +
" defined on " + target);
}
Object newTarget = MethodUtil.invoke(getter, target, new Object[]{});
return applyGetters(newTarget, rest);
}
catch (Exception e) {
throw new RuntimeException("Failed to call method: " + first +
" on " + target, e);
}
}
/**
* Extract the appropriate property value from the event and
* pass it to the action associated with
* this <code>EventHandler</code>.
*
* @param proxy the proxy object
* @param method the method in the listener interface
* @return the result of applying the action to the target
*
* @see EventHandler
*/
public Object invoke(final Object proxy, final Method method, final Object[] arguments) {
AccessControlContext acc = this.acc;
if ((acc == null) && (System.getSecurityManager() != null)) {
throw new SecurityException("AccessControlContext is not set");
}
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return invokeInternal(proxy, method, arguments);
}
}, acc);
}
private Object invokeInternal(Object proxy, Method method, Object[] arguments) {
String methodName = method.getName();
if (method.getDeclaringClass() == Object.class) {
// Handle the Object public methods.
if (methodName.equals("hashCode")) {
return new Integer(System.identityHashCode(proxy));
} else if (methodName.equals("equals")) {
return (proxy == arguments[0] ? Boolean.TRUE : Boolean.FALSE);
} else if (methodName.equals("toString")) {
return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode());
}
}
if (listenerMethodName == null || listenerMethodName.equals(methodName)) {
Class[] argTypes = null;
Object[] newArgs = null;
if (eventPropertyName == null) { // Nullary method.
newArgs = new Object[]{};
argTypes = new Class<?>[]{};
}
else {
Object input = applyGetters(arguments[0], getEventPropertyName());
newArgs = new Object[]{input};
argTypes = new Class<?>[]{input == null ? null :
input.getClass()};
}
try {
int lastDot = action.lastIndexOf('.');
if (lastDot != -1) {
target = applyGetters(target, action.substring(0, lastDot));
action = action.substring(lastDot + 1);
}
Method targetMethod = Statement.getMethod(
target.getClass(), action, argTypes);
if (targetMethod == null) {
targetMethod = Statement.getMethod(target.getClass(),
"set" + NameGenerator.capitalize(action), argTypes);
}
if (targetMethod == null) {
String argTypeString = (argTypes.length == 0)
? " with no arguments"
: " with argument " + argTypes[0];
throw new RuntimeException(
"No method called " + action + " on " +
target.getClass() + argTypeString);
}
return MethodUtil.invoke(targetMethod, target, newArgs);
}
catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
throw (th instanceof RuntimeException)
? (RuntimeException) th
: new RuntimeException(th);
}
}
return null;
}
/**
* Creates an implementation of <code>listenerInterface</code> in which
* <em>all</em> of the methods in the listener interface apply
* the handler's <code>action</code> to the <code>target</code>. This
* method is implemented by calling the other, more general,
* implementation of the <code>create</code> method with both
* the <code>eventPropertyName</code> and the <code>listenerMethodName</code>
* taking the value <code>null</code>. Refer to
* {@link java.beans.EventHandler#create(Class, Object, String, String)
* the general version of create} for a complete description of
* the <code>action</code> parameter.
* <p>
* To create an <code>ActionListener</code> that shows a
* <code>JDialog</code> with <code>dialog.show()</code>,
* one can write:
*
*<blockquote>
*<pre>
*EventHandler.create(ActionListener.class, dialog, "show")
*</pre>
*</blockquote>
*
* @param <T> the type to create
* @param listenerInterface the listener interface to create a proxy for
* @param target the object that will perform the action
* @param action the name of a (possibly qualified) property or method on
* the target
* @return an object that implements <code>listenerInterface</code>
*
* @throws NullPointerException if <code>listenerInterface</code> is null
* @throws NullPointerException if <code>target</code> is null
* @throws NullPointerException if <code>action</code> is null
*
* @see #create(Class, Object, String, String)
*/
public static <T> T create(Class<T> listenerInterface,
Object target, String action)
{
return create(listenerInterface, target, action, null, null);
}
/**
/**
* Creates an implementation of <code>listenerInterface</code> in which
* <em>all</em> of the methods pass the value of the event
* expression, <code>eventPropertyName</code>, to the final method in the
* statement, <code>action</code>, which is applied to the <code>target</code>.
* This method is implemented by calling the
* more general, implementation of the <code>create</code> method with
* the <code>listenerMethodName</code> taking the value <code>null</code>.
* Refer to
* {@link java.beans.EventHandler#create(Class, Object, String, String)
* the general version of create} for a complete description of
* the <code>action</code> and <code>eventPropertyName</code> parameters.
* <p>
* To create an <code>ActionListener</code> that sets the
* the text of a <code>JLabel</code> to the text value of
* the <code>JTextField</code> source of the incoming event,
* you can use the following code:
*
*<blockquote>
*<pre>
*EventHandler.create(ActionListener.class, label, "text", "source.text");
*</pre>
*</blockquote>
*
* This is equivalent to the following code:
*<blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*new ActionListener() {
* public void actionPerformed(ActionEvent event) {
* label.setText(((JTextField)(event.getSource())).getText());
* }
*};
*</pre>
*</blockquote>
*
* @param <T> the type to create
* @param listenerInterface the listener interface to create a proxy for
* @param target the object that will perform the action
* @param action the name of a (possibly qualified) property or method on
* the target
* @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
*
* @return an object that implements <code>listenerInterface</code>
*
* @throws NullPointerException if <code>listenerInterface</code> is null
* @throws NullPointerException if <code>target</code> is null
* @throws NullPointerException if <code>action</code> is null
*
* @see #create(Class, Object, String, String, String)
*/
public static <T> T create(Class<T> listenerInterface,
Object target, String action,
String eventPropertyName)
{
return create(listenerInterface, target, action, eventPropertyName, null);
}
/**
* Creates an implementation of <code>listenerInterface</code> in which
* the method named <code>listenerMethodName</code>
* passes the value of the event expression, <code>eventPropertyName</code>,
* to the final method in the statement, <code>action</code>, which
* is applied to the <code>target</code>. All of the other listener
* methods do nothing.
* <p>
* The <code>eventPropertyName</code> string is used to extract a value
* from the incoming event object that is passed to the target
* method. The common case is the target method takes no arguments, in
* which case a value of null should be used for the
* <code>eventPropertyName</code>. Alternatively if you want
* the incoming event object passed directly to the target method use
* the empty string.
* The format of the <code>eventPropertyName</code> string is a sequence of
* methods or properties where each method or
* property is applied to the value returned by the preceding method
* starting from the incoming event object.
* The syntax is: <code>propertyName{.propertyName}*</code>
* where <code>propertyName</code> matches a method or
* property. For example, to extract the <code>point</code>
* property from a <code>MouseEvent</code>, you could use either
* <code>"point"</code> or <code>"getPoint"</code> as the
* <code>eventPropertyName</code>. To extract the "text" property from
* a <code>MouseEvent</code> with a <code>JLabel</code> source use any
* of the following as <code>eventPropertyName</code>:
* <code>"source.text"</code>,
* <code>"getSource.text"</code> <code>"getSource.getText"</code> or
* <code>"source.getText"</code>. If a method can not be found, or an
* exception is generated as part of invoking a method a
* <code>RuntimeException</code> will be thrown at dispatch time. For
* example, if the incoming event object is null, and
* <code>eventPropertyName</code> is non-null and not empty, a
* <code>RuntimeException</code> will be thrown.
* <p>
* The <code>action</code> argument is of the same format as the
* <code>eventPropertyName</code> argument where the last property name
* identifies either a method name or writable property.
* <p>
* If the <code>listenerMethodName</code> is <code>null</code>
* <em>all</em> methods in the interface trigger the <code>action</code> to be
* executed on the <code>target</code>.
* <p>
* For example, to create a <code>MouseListener</code> that sets the target
* object's <code>origin</code> property to the incoming <code>MouseEvent</code>'s
* location (that's the value of <code>mouseEvent.getPoint()</code>) each
* time a mouse button is pressed, one would write:
*<blockquote>
*<pre>
*EventHandler.create(MouseListener.class, target, "origin", "point", "mousePressed");
*</pre>
*</blockquote>
*
* This is comparable to writing a <code>MouseListener</code> in which all
* of the methods except <code>mousePressed</code> are no-ops:
*
*<blockquote>
*<pre>
//Equivalent code using an inner class instead of EventHandler.
*new MouseAdapter() {
* public void mousePressed(MouseEvent e) {
* target.setOrigin(e.getPoint());
* }
*};
* </pre>
*</blockquote>
*
* @param <T> the type to create
* @param listenerInterface the listener interface to create a proxy for
* @param target the object that will perform the action
* @param action the name of a (possibly qualified) property or method on
* the target
* @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
* @param listenerMethodName the name of the method in the listener interface that should trigger the action
*
* @return an object that implements <code>listenerInterface</code>
*
* @throws NullPointerException if <code>listenerInterface</code> is null
* @throws NullPointerException if <code>target</code> is null
* @throws NullPointerException if <code>action</code> is null
*
* @see EventHandler
*/
public static <T> T create(Class<T> listenerInterface,
Object target, String action,
String eventPropertyName,
String listenerMethodName)
{
// Create this first to verify target/action are non-null
final EventHandler handler = new EventHandler(target, action,
eventPropertyName,
listenerMethodName);
if (listenerInterface == null) {
throw new NullPointerException(
"listenerInterface must be non-null");
}
final ClassLoader loader = getClassLoader(listenerInterface);
final Class<?>[] interfaces = {listenerInterface};
return AccessController.doPrivileged(new PrivilegedAction<T>() {
@SuppressWarnings("unchecked")
public T run() {
return (T) Proxy.newProxyInstance(loader, interfaces, handler);
}
});
}
private static ClassLoader getClassLoader(Class<?> type) {
ReflectUtil.checkPackageAccess(type);
ClassLoader loader = type.getClassLoader();
if (loader == null) {
loader = Thread.currentThread().getContextClassLoader(); // avoid use of BCP
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
}
return loader;
}
}

View File

@@ -0,0 +1,540 @@
/*
* Copyright (c) 1996, 2012, 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 java.lang.ref.Reference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* An EventSetDescriptor describes a group of events that a given Java
* bean fires.
* <P>
* The given group of events are all delivered as method calls on a single
* event listener interface, and an event listener object can be registered
* via a call on a registration method supplied by the event source.
*/
public class EventSetDescriptor extends FeatureDescriptor {
private MethodDescriptor[] listenerMethodDescriptors;
private MethodDescriptor addMethodDescriptor;
private MethodDescriptor removeMethodDescriptor;
private MethodDescriptor getMethodDescriptor;
private Reference<Method[]> listenerMethodsRef;
private Reference<? extends Class<?>> listenerTypeRef;
private boolean unicast;
private boolean inDefaultEventSet = true;
/**
* Creates an <TT>EventSetDescriptor</TT> assuming that you are
* following the most simple standard design pattern where a named
* event &quot;fred&quot; is (1) delivered as a call on the single method of
* interface FredListener, (2) has a single argument of type FredEvent,
* and (3) where the FredListener may be registered with a call on an
* addFredListener method of the source component and removed with a
* call on a removeFredListener method.
*
* @param sourceClass The class firing the event.
* @param eventSetName The programmatic name of the event. E.g. &quot;fred&quot;.
* Note that this should normally start with a lower-case character.
* @param listenerType The target interface that events
* will get delivered to.
* @param listenerMethodName The method that will get called when the event gets
* delivered to its target listener interface.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public EventSetDescriptor(Class<?> sourceClass, String eventSetName,
Class<?> listenerType, String listenerMethodName)
throws IntrospectionException {
this(sourceClass, eventSetName, listenerType,
new String[] { listenerMethodName },
Introspector.ADD_PREFIX + getListenerClassName(listenerType),
Introspector.REMOVE_PREFIX + getListenerClassName(listenerType),
Introspector.GET_PREFIX + getListenerClassName(listenerType) + "s");
String eventName = NameGenerator.capitalize(eventSetName) + "Event";
Method[] listenerMethods = getListenerMethods();
if (listenerMethods.length > 0) {
Class[] args = getParameterTypes(getClass0(), listenerMethods[0]);
// Check for EventSet compliance. Special case for vetoableChange. See 4529996
if (!"vetoableChange".equals(eventSetName) && !args[0].getName().endsWith(eventName)) {
throw new IntrospectionException("Method \"" + listenerMethodName +
"\" should have argument \"" +
eventName + "\"");
}
}
}
private static String getListenerClassName(Class<?> cls) {
String className = cls.getName();
return className.substring(className.lastIndexOf('.') + 1);
}
/**
* Creates an <TT>EventSetDescriptor</TT> from scratch using
* string names.
*
* @param sourceClass The class firing the event.
* @param eventSetName The programmatic name of the event set.
* Note that this should normally start with a lower-case character.
* @param listenerType The Class of the target interface that events
* will get delivered to.
* @param listenerMethodNames The names of the methods that will get called
* when the event gets delivered to its target listener interface.
* @param addListenerMethodName The name of the method on the event source
* that can be used to register an event listener object.
* @param removeListenerMethodName The name of the method on the event source
* that can be used to de-register an event listener object.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public EventSetDescriptor(Class<?> sourceClass,
String eventSetName,
Class<?> listenerType,
String listenerMethodNames[],
String addListenerMethodName,
String removeListenerMethodName)
throws IntrospectionException {
this(sourceClass, eventSetName, listenerType,
listenerMethodNames, addListenerMethodName,
removeListenerMethodName, null);
}
/**
* This constructor creates an EventSetDescriptor from scratch using
* string names.
*
* @param sourceClass The class firing the event.
* @param eventSetName The programmatic name of the event set.
* Note that this should normally start with a lower-case character.
* @param listenerType The Class of the target interface that events
* will get delivered to.
* @param listenerMethodNames The names of the methods that will get called
* when the event gets delivered to its target listener interface.
* @param addListenerMethodName The name of the method on the event source
* that can be used to register an event listener object.
* @param removeListenerMethodName The name of the method on the event source
* that can be used to de-register an event listener object.
* @param getListenerMethodName The method on the event source that
* can be used to access the array of event listener objects.
* @exception IntrospectionException if an exception occurs during
* introspection.
* @since 1.4
*/
public EventSetDescriptor(Class<?> sourceClass,
String eventSetName,
Class<?> listenerType,
String listenerMethodNames[],
String addListenerMethodName,
String removeListenerMethodName,
String getListenerMethodName)
throws IntrospectionException {
if (sourceClass == null || eventSetName == null || listenerType == null) {
throw new NullPointerException();
}
setName(eventSetName);
setClass0(sourceClass);
setListenerType(listenerType);
Method[] listenerMethods = new Method[listenerMethodNames.length];
for (int i = 0; i < listenerMethodNames.length; i++) {
// Check for null names
if (listenerMethodNames[i] == null) {
throw new NullPointerException();
}
listenerMethods[i] = getMethod(listenerType, listenerMethodNames[i], 1);
}
setListenerMethods(listenerMethods);
setAddListenerMethod(getMethod(sourceClass, addListenerMethodName, 1));
setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1));
// Be more forgiving of not finding the getListener method.
Method method = Introspector.findMethod(sourceClass, getListenerMethodName, 0);
if (method != null) {
setGetListenerMethod(method);
}
}
private static Method getMethod(Class<?> cls, String name, int args)
throws IntrospectionException {
if (name == null) {
return null;
}
Method method = Introspector.findMethod(cls, name, args);
if ((method == null) || Modifier.isStatic(method.getModifiers())) {
throw new IntrospectionException("Method not found: " + name +
" on class " + cls.getName());
}
return method;
}
/**
* Creates an <TT>EventSetDescriptor</TT> from scratch using
* <TT>java.lang.reflect.Method</TT> and <TT>java.lang.Class</TT> objects.
*
* @param eventSetName The programmatic name of the event set.
* @param listenerType The Class for the listener interface.
* @param listenerMethods An array of Method objects describing each
* of the event handling methods in the target listener.
* @param addListenerMethod The method on the event source
* that can be used to register an event listener object.
* @param removeListenerMethod The method on the event source
* that can be used to de-register an event listener object.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public EventSetDescriptor(String eventSetName,
Class<?> listenerType,
Method listenerMethods[],
Method addListenerMethod,
Method removeListenerMethod)
throws IntrospectionException {
this(eventSetName, listenerType, listenerMethods,
addListenerMethod, removeListenerMethod, null);
}
/**
* This constructor creates an EventSetDescriptor from scratch using
* java.lang.reflect.Method and java.lang.Class objects.
*
* @param eventSetName The programmatic name of the event set.
* @param listenerType The Class for the listener interface.
* @param listenerMethods An array of Method objects describing each
* of the event handling methods in the target listener.
* @param addListenerMethod The method on the event source
* that can be used to register an event listener object.
* @param removeListenerMethod The method on the event source
* that can be used to de-register an event listener object.
* @param getListenerMethod The method on the event source
* that can be used to access the array of event listener objects.
* @exception IntrospectionException if an exception occurs during
* introspection.
* @since 1.4
*/
public EventSetDescriptor(String eventSetName,
Class<?> listenerType,
Method listenerMethods[],
Method addListenerMethod,
Method removeListenerMethod,
Method getListenerMethod)
throws IntrospectionException {
setName(eventSetName);
setListenerMethods(listenerMethods);
setAddListenerMethod(addListenerMethod);
setRemoveListenerMethod( removeListenerMethod);
setGetListenerMethod(getListenerMethod);
setListenerType(listenerType);
}
/**
* Creates an <TT>EventSetDescriptor</TT> from scratch using
* <TT>java.lang.reflect.MethodDescriptor</TT> and <TT>java.lang.Class</TT>
* objects.
*
* @param eventSetName The programmatic name of the event set.
* @param listenerType The Class for the listener interface.
* @param listenerMethodDescriptors An array of MethodDescriptor objects
* describing each of the event handling methods in the
* target listener.
* @param addListenerMethod The method on the event source
* that can be used to register an event listener object.
* @param removeListenerMethod The method on the event source
* that can be used to de-register an event listener object.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public EventSetDescriptor(String eventSetName,
Class<?> listenerType,
MethodDescriptor listenerMethodDescriptors[],
Method addListenerMethod,
Method removeListenerMethod)
throws IntrospectionException {
setName(eventSetName);
this.listenerMethodDescriptors = (listenerMethodDescriptors != null)
? listenerMethodDescriptors.clone()
: null;
setAddListenerMethod(addListenerMethod);
setRemoveListenerMethod(removeListenerMethod);
setListenerType(listenerType);
}
/**
* Gets the <TT>Class</TT> object for the target interface.
*
* @return The Class object for the target interface that will
* get invoked when the event is fired.
*/
public Class<?> getListenerType() {
return (this.listenerTypeRef != null)
? this.listenerTypeRef.get()
: null;
}
private void setListenerType(Class<?> cls) {
this.listenerTypeRef = getWeakReference(cls);
}
/**
* Gets the methods of the target listener interface.
*
* @return An array of <TT>Method</TT> objects for the target methods
* within the target listener interface that will get called when
* events are fired.
*/
public synchronized Method[] getListenerMethods() {
Method[] methods = getListenerMethods0();
if (methods == null) {
if (listenerMethodDescriptors != null) {
methods = new Method[listenerMethodDescriptors.length];
for (int i = 0; i < methods.length; i++) {
methods[i] = listenerMethodDescriptors[i].getMethod();
}
}
setListenerMethods(methods);
}
return methods;
}
private void setListenerMethods(Method[] methods) {
if (methods == null) {
return;
}
if (listenerMethodDescriptors == null) {
listenerMethodDescriptors = new MethodDescriptor[methods.length];
for (int i = 0; i < methods.length; i++) {
listenerMethodDescriptors[i] = new MethodDescriptor(methods[i]);
}
}
this.listenerMethodsRef = getSoftReference(methods);
}
private Method[] getListenerMethods0() {
return (this.listenerMethodsRef != null)
? this.listenerMethodsRef.get()
: null;
}
/**
* Gets the <code>MethodDescriptor</code>s of the target listener interface.
*
* @return An array of <code>MethodDescriptor</code> objects for the target methods
* within the target listener interface that will get called when
* events are fired.
*/
public synchronized MethodDescriptor[] getListenerMethodDescriptors() {
return (this.listenerMethodDescriptors != null)
? this.listenerMethodDescriptors.clone()
: null;
}
/**
* Gets the method used to add event listeners.
*
* @return The method used to register a listener at the event source.
*/
public synchronized Method getAddListenerMethod() {
return getMethod(this.addMethodDescriptor);
}
private synchronized void setAddListenerMethod(Method method) {
if (method == null) {
return;
}
if (getClass0() == null) {
setClass0(method.getDeclaringClass());
}
addMethodDescriptor = new MethodDescriptor(method);
setTransient(method.getAnnotation(Transient.class));
}
/**
* Gets the method used to remove event listeners.
*
* @return The method used to remove a listener at the event source.
*/
public synchronized Method getRemoveListenerMethod() {
return getMethod(this.removeMethodDescriptor);
}
private synchronized void setRemoveListenerMethod(Method method) {
if (method == null) {
return;
}
if (getClass0() == null) {
setClass0(method.getDeclaringClass());
}
removeMethodDescriptor = new MethodDescriptor(method);
setTransient(method.getAnnotation(Transient.class));
}
/**
* Gets the method used to access the registered event listeners.
*
* @return The method used to access the array of listeners at the event
* source or null if it doesn't exist.
* @since 1.4
*/
public synchronized Method getGetListenerMethod() {
return getMethod(this.getMethodDescriptor);
}
private synchronized void setGetListenerMethod(Method method) {
if (method == null) {
return;
}
if (getClass0() == null) {
setClass0(method.getDeclaringClass());
}
getMethodDescriptor = new MethodDescriptor(method);
setTransient(method.getAnnotation(Transient.class));
}
/**
* Mark an event set as unicast (or not).
*
* @param unicast True if the event set is unicast.
*/
public void setUnicast(boolean unicast) {
this.unicast = unicast;
}
/**
* Normally event sources are multicast. However there are some
* exceptions that are strictly unicast.
*
* @return <TT>true</TT> if the event set is unicast.
* Defaults to <TT>false</TT>.
*/
public boolean isUnicast() {
return unicast;
}
/**
* Marks an event set as being in the &quot;default&quot; set (or not).
* By default this is <TT>true</TT>.
*
* @param inDefaultEventSet <code>true</code> if the event set is in
* the &quot;default&quot; set,
* <code>false</code> if not
*/
public void setInDefaultEventSet(boolean inDefaultEventSet) {
this.inDefaultEventSet = inDefaultEventSet;
}
/**
* Reports if an event set is in the &quot;default&quot; set.
*
* @return <TT>true</TT> if the event set is in
* the &quot;default&quot; set. Defaults to <TT>true</TT>.
*/
public boolean isInDefaultEventSet() {
return inDefaultEventSet;
}
/*
* Package-private constructor
* Merge two event set descriptors. Where they conflict, give the
* second argument (y) priority over the first argument (x).
*
* @param x The first (lower priority) EventSetDescriptor
* @param y The second (higher priority) EventSetDescriptor
*/
EventSetDescriptor(EventSetDescriptor x, EventSetDescriptor y) {
super(x,y);
listenerMethodDescriptors = x.listenerMethodDescriptors;
if (y.listenerMethodDescriptors != null) {
listenerMethodDescriptors = y.listenerMethodDescriptors;
}
listenerTypeRef = x.listenerTypeRef;
if (y.listenerTypeRef != null) {
listenerTypeRef = y.listenerTypeRef;
}
addMethodDescriptor = x.addMethodDescriptor;
if (y.addMethodDescriptor != null) {
addMethodDescriptor = y.addMethodDescriptor;
}
removeMethodDescriptor = x.removeMethodDescriptor;
if (y.removeMethodDescriptor != null) {
removeMethodDescriptor = y.removeMethodDescriptor;
}
getMethodDescriptor = x.getMethodDescriptor;
if (y.getMethodDescriptor != null) {
getMethodDescriptor = y.getMethodDescriptor;
}
unicast = y.unicast;
if (!x.inDefaultEventSet || !y.inDefaultEventSet) {
inDefaultEventSet = false;
}
}
/*
* Package-private dup constructor
* This must isolate the new object from any changes to the old object.
*/
EventSetDescriptor(EventSetDescriptor old) {
super(old);
if (old.listenerMethodDescriptors != null) {
int len = old.listenerMethodDescriptors.length;
listenerMethodDescriptors = new MethodDescriptor[len];
for (int i = 0; i < len; i++) {
listenerMethodDescriptors[i] = new MethodDescriptor(
old.listenerMethodDescriptors[i]);
}
}
listenerTypeRef = old.listenerTypeRef;
addMethodDescriptor = old.addMethodDescriptor;
removeMethodDescriptor = old.removeMethodDescriptor;
getMethodDescriptor = old.getMethodDescriptor;
unicast = old.unicast;
inDefaultEventSet = old.inDefaultEventSet;
}
void appendTo(StringBuilder sb) {
appendTo(sb, "unicast", this.unicast);
appendTo(sb, "inDefaultEventSet", this.inDefaultEventSet);
appendTo(sb, "listenerType", this.listenerTypeRef);
appendTo(sb, "getListenerMethod", getMethod(this.getMethodDescriptor));
appendTo(sb, "addListenerMethod", getMethod(this.addMethodDescriptor));
appendTo(sb, "removeListenerMethod", getMethod(this.removeMethodDescriptor));
}
private static Method getMethod(MethodDescriptor descriptor) {
return (descriptor != null)
? descriptor.getMethod()
: null;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2000, 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;
/**
* An ExceptionListener is notified of internal exceptions.
*
* @since 1.4
*
* @author Philip Milne
*/
public interface ExceptionListener {
/**
* This method is called when a recoverable exception has
* been caught.
*
* @param e The exception that was caught.
*
*/
public void exceptionThrown(Exception e);
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright (c) 2000, 2013, 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;
/**
* An <code>Expression</code> object represents a primitive expression
* in which a single method is applied to a target and a set of
* arguments to return a result - as in <code>"a.getFoo()"</code>.
* <p>
* In addition to the properties of the super class, the
* <code>Expression</code> object provides a <em>value</em> which
* is the object returned when this expression is evaluated.
* The return value is typically not provided by the caller and
* is instead computed by dynamically finding the method and invoking
* it when the first call to <code>getValue</code> is made.
*
* @see #getValue
* @see #setValue
*
* @since 1.4
*
* @author Philip Milne
*/
public class Expression extends Statement {
private static Object unbound = new Object();
private Object value = unbound;
/**
* Creates a new {@link Expression} object
* for the specified target object to invoke the method
* specified by the name and by the array of arguments.
* <p>
* The {@code target} and the {@code methodName} values should not be {@code null}.
* Otherwise an attempt to execute this {@code Expression}
* will result in a {@code NullPointerException}.
* If the {@code arguments} value is {@code null},
* an empty array is used as the value of the {@code arguments} property.
*
* @param target the target object of this expression
* @param methodName the name of the method to invoke on the specified target
* @param arguments the array of arguments to invoke the specified method
*
* @see #getValue
*/
@ConstructorProperties({"target", "methodName", "arguments"})
public Expression(Object target, String methodName, Object[] arguments) {
super(target, methodName, arguments);
}
/**
* Creates a new {@link Expression} object with the specified value
* for the specified target object to invoke the method
* specified by the name and by the array of arguments.
* The {@code value} value is used as the value of the {@code value} property,
* so the {@link #getValue} method will return it
* without executing this {@code Expression}.
* <p>
* The {@code target} and the {@code methodName} values should not be {@code null}.
* Otherwise an attempt to execute this {@code Expression}
* will result in a {@code NullPointerException}.
* If the {@code arguments} value is {@code null},
* an empty array is used as the value of the {@code arguments} property.
*
* @param value the value of this expression
* @param target the target object of this expression
* @param methodName the name of the method to invoke on the specified target
* @param arguments the array of arguments to invoke the specified method
*
* @see #setValue
*/
public Expression(Object value, Object target, String methodName, Object[] arguments) {
this(target, methodName, arguments);
setValue(value);
}
/**
* {@inheritDoc}
* <p>
* If the invoked method completes normally,
* the value it returns is copied in the {@code value} property.
* Note that the {@code value} property is set to {@code null},
* if the return type of the underlying method is {@code void}.
*
* @throws NullPointerException if the value of the {@code target} or
* {@code methodName} property is {@code null}
* @throws NoSuchMethodException if a matching method is not found
* @throws SecurityException if a security manager exists and
* it denies the method invocation
* @throws Exception that is thrown by the invoked method
*
* @see java.lang.reflect.Method
* @since 1.7
*/
@Override
public void execute() throws Exception {
setValue(invoke());
}
/**
* If the value property of this instance is not already set,
* this method dynamically finds the method with the specified
* methodName on this target with these arguments and calls it.
* The result of the method invocation is first copied
* into the value property of this expression and then returned
* as the result of <code>getValue</code>. If the value property
* was already set, either by a call to <code>setValue</code>
* or a previous call to <code>getValue</code> then the value
* property is returned without either looking up or calling the method.
* <p>
* The value property of an <code>Expression</code> is set to
* a unique private (non-<code>null</code>) value by default and
* this value is used as an internal indication that the method
* has not yet been called. A return value of <code>null</code>
* replaces this default value in the same way that any other value
* would, ensuring that expressions are never evaluated more than once.
* <p>
* See the <code>execute</code> method for details on how
* methods are chosen using the dynamic types of the target
* and arguments.
*
* @see Statement#execute
* @see #setValue
*
* @return The result of applying this method to these arguments.
* @throws Exception if the method with the specified methodName
* throws an exception
*/
public Object getValue() throws Exception {
if (value == unbound) {
setValue(invoke());
}
return value;
}
/**
* Sets the value of this expression to <code>value</code>.
* This value will be returned by the getValue method
* without calling the method associated with this
* expression.
*
* @param value The value of this expression.
*
* @see #getValue
*/
public void setValue(Object value) {
this.value = value;
}
/*pp*/ String instanceName(Object instance) {
return instance == unbound ? "<unbound>" : super.instanceName(instance);
}
/**
* Prints the value of this expression using a Java-style syntax.
*/
public String toString() {
return instanceName(value) + "=" + super.toString();
}
}

View File

@@ -0,0 +1,445 @@
/*
* Copyright (c) 1996, 2011, 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<? 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);
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2003, 2011, 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;
/**
* An "IndexedPropertyChange" event gets delivered whenever a component that
* conforms to the JavaBeans&trade; specification (a "bean") changes a bound
* indexed property. This class is an extension of <code>PropertyChangeEvent</code>
* but contains the index of the property that has changed.
* <P>
* Null values may be provided for the old and the new values if their
* true values are not known.
* <P>
* An event source may send a null object as the name to indicate that an
* arbitrary set of if its properties have changed. In this case the
* old and new values should also be null.
*
* @since 1.5
* @author Mark Davidson
*/
public class IndexedPropertyChangeEvent extends PropertyChangeEvent {
private static final long serialVersionUID = -320227448495806870L;
private int index;
/**
* Constructs a new <code>IndexedPropertyChangeEvent</code> object.
*
* @param source The bean that fired the event.
* @param propertyName The programmatic name of the property that
* was changed.
* @param oldValue The old value of the property.
* @param newValue The new value of the property.
* @param index index of the property element that was changed.
*/
public IndexedPropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue,
int index) {
super (source, propertyName, oldValue, newValue);
this.index = index;
}
/**
* Gets the index of the property that was changed.
*
* @return The index specifying the property element that was
* changed.
*/
public int getIndex() {
return index;
}
void appendTo(StringBuilder sb) {
sb.append("; index=").append(getIndex());
}
}

View File

@@ -0,0 +1,523 @@
/*
* Copyright (c) 1996, 2013, 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 java.lang.ref.Reference;
import java.lang.reflect.Method;
/**
* An IndexedPropertyDescriptor describes a property that acts like an
* array and has an indexed read and/or indexed write method to access
* specific elements of the array.
* <p>
* An indexed property may also provide simple non-indexed read and write
* methods. If these are present, they read and write arrays of the type
* returned by the indexed read method.
*/
public class IndexedPropertyDescriptor extends PropertyDescriptor {
private Reference<? extends Class<?>> indexedPropertyTypeRef;
private final MethodRef indexedReadMethodRef = new MethodRef();
private final MethodRef indexedWriteMethodRef = new MethodRef();
private String indexedReadMethodName;
private String indexedWriteMethodName;
/**
* This constructor constructs an IndexedPropertyDescriptor for a property
* that follows the standard Java conventions by having getFoo and setFoo
* accessor methods, for both indexed access and array access.
* <p>
* Thus if the argument name is "fred", it will assume that there
* is an indexed reader method "getFred", a non-indexed (array) reader
* method also called "getFred", an indexed writer method "setFred",
* and finally a non-indexed writer method "setFred".
*
* @param propertyName The programmatic name of the property.
* @param beanClass The Class object for the target bean.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)
throws IntrospectionException {
this(propertyName, beanClass,
Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName),
Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName),
Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName),
Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));
}
/**
* This constructor takes the name of a simple property, and method
* names for reading and writing the property, both indexed
* and non-indexed.
*
* @param propertyName The programmatic name of the property.
* @param beanClass The Class object for the target bean.
* @param readMethodName The name of the method used for reading the property
* values as an array. May be null if the property is write-only
* or must be indexed.
* @param writeMethodName The name of the method used for writing the property
* values as an array. May be null if the property is read-only
* or must be indexed.
* @param indexedReadMethodName The name of the method used for reading
* an indexed property value.
* May be null if the property is write-only.
* @param indexedWriteMethodName The name of the method used for writing
* an indexed property value.
* May be null if the property is read-only.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,
String readMethodName, String writeMethodName,
String indexedReadMethodName, String indexedWriteMethodName)
throws IntrospectionException {
super(propertyName, beanClass, readMethodName, writeMethodName);
this.indexedReadMethodName = indexedReadMethodName;
if (indexedReadMethodName != null && getIndexedReadMethod() == null) {
throw new IntrospectionException("Method not found: " + indexedReadMethodName);
}
this.indexedWriteMethodName = indexedWriteMethodName;
if (indexedWriteMethodName != null && getIndexedWriteMethod() == null) {
throw new IntrospectionException("Method not found: " + indexedWriteMethodName);
}
// Implemented only for type checking.
findIndexedPropertyType(getIndexedReadMethod(), getIndexedWriteMethod());
}
/**
* This constructor takes the name of a simple property, and Method
* objects for reading and writing the property.
*
* @param propertyName The programmatic name of the property.
* @param readMethod The method used for reading the property values as an array.
* May be null if the property is write-only or must be indexed.
* @param writeMethod The method used for writing the property values as an array.
* May be null if the property is read-only or must be indexed.
* @param indexedReadMethod The method used for reading an indexed property value.
* May be null if the property is write-only.
* @param indexedWriteMethod The method used for writing an indexed property value.
* May be null if the property is read-only.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public IndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod,
Method indexedReadMethod, Method indexedWriteMethod)
throws IntrospectionException {
super(propertyName, readMethod, writeMethod);
setIndexedReadMethod0(indexedReadMethod);
setIndexedWriteMethod0(indexedWriteMethod);
// Type checking
setIndexedPropertyType(findIndexedPropertyType(indexedReadMethod, indexedWriteMethod));
}
/**
* Creates <code>PropertyDescriptor</code> for the specified bean
* with the specified name and methods to read/write the property value.
*
* @param bean the type of the target bean
* @param base the base name of the property (the rest of the method name)
* @param read the method used for reading the property value
* @param write the method used for writing the property value
* @param readIndexed the method used for reading an indexed property value
* @param writeIndexed the method used for writing an indexed property value
* @exception IntrospectionException if an exception occurs during introspection
*
* @since 1.7
*/
IndexedPropertyDescriptor(Class<?> bean, String base, Method read, Method write, Method readIndexed, Method writeIndexed) throws IntrospectionException {
super(bean, base, read, write);
setIndexedReadMethod0(readIndexed);
setIndexedWriteMethod0(writeIndexed);
// Type checking
setIndexedPropertyType(findIndexedPropertyType(readIndexed, writeIndexed));
}
/**
* Gets the method that should be used to read an indexed
* property value.
*
* @return The method that should be used to read an indexed
* property value.
* May return null if the property isn't indexed or is write-only.
*/
public synchronized Method getIndexedReadMethod() {
Method indexedReadMethod = this.indexedReadMethodRef.get();
if (indexedReadMethod == null) {
Class<?> cls = getClass0();
if (cls == null ||
(indexedReadMethodName == null && !this.indexedReadMethodRef.isSet())) {
// the Indexed readMethod was explicitly set to null.
return null;
}
String nextMethodName = Introspector.GET_PREFIX + getBaseName();
if (indexedReadMethodName == null) {
Class<?> type = getIndexedPropertyType0();
if (type == boolean.class || type == null) {
indexedReadMethodName = Introspector.IS_PREFIX + getBaseName();
} else {
indexedReadMethodName = nextMethodName;
}
}
Class<?>[] args = { int.class };
indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args);
if ((indexedReadMethod == null) && !indexedReadMethodName.equals(nextMethodName)) {
// no "is" method, so look for a "get" method.
indexedReadMethodName = nextMethodName;
indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args);
}
setIndexedReadMethod0(indexedReadMethod);
}
return indexedReadMethod;
}
/**
* Sets the method that should be used to read an indexed property value.
*
* @param readMethod The new indexed read method.
* @throws IntrospectionException if an exception occurs during
* introspection.
*/
public synchronized void setIndexedReadMethod(Method readMethod)
throws IntrospectionException {
// the indexed property type is set by the reader.
setIndexedPropertyType(findIndexedPropertyType(readMethod,
this.indexedWriteMethodRef.get()));
setIndexedReadMethod0(readMethod);
}
private void setIndexedReadMethod0(Method readMethod) {
this.indexedReadMethodRef.set(readMethod);
if (readMethod == null) {
indexedReadMethodName = null;
return;
}
setClass0(readMethod.getDeclaringClass());
indexedReadMethodName = readMethod.getName();
setTransient(readMethod.getAnnotation(Transient.class));
}
/**
* Gets the method that should be used to write an indexed property value.
*
* @return The method that should be used to write an indexed
* property value.
* May return null if the property isn't indexed or is read-only.
*/
public synchronized Method getIndexedWriteMethod() {
Method indexedWriteMethod = this.indexedWriteMethodRef.get();
if (indexedWriteMethod == null) {
Class<?> cls = getClass0();
if (cls == null ||
(indexedWriteMethodName == null && !this.indexedWriteMethodRef.isSet())) {
// the Indexed writeMethod was explicitly set to null.
return null;
}
// We need the indexed type to ensure that we get the correct method.
// Cannot use the getIndexedPropertyType method since that could
// result in an infinite loop.
Class<?> type = getIndexedPropertyType0();
if (type == null) {
try {
type = findIndexedPropertyType(getIndexedReadMethod(), null);
setIndexedPropertyType(type);
} catch (IntrospectionException ex) {
// Set iprop type to be the classic type
Class<?> propType = getPropertyType();
if (propType.isArray()) {
type = propType.getComponentType();
}
}
}
if (indexedWriteMethodName == null) {
indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName();
}
Class<?>[] args = (type == null) ? null : new Class<?>[] { int.class, type };
indexedWriteMethod = Introspector.findMethod(cls, indexedWriteMethodName, 2, args);
if (indexedWriteMethod != null) {
if (!indexedWriteMethod.getReturnType().equals(void.class)) {
indexedWriteMethod = null;
}
}
setIndexedWriteMethod0(indexedWriteMethod);
}
return indexedWriteMethod;
}
/**
* Sets the method that should be used to write an indexed property value.
*
* @param writeMethod The new indexed write method.
* @throws IntrospectionException if an exception occurs during
* introspection.
*/
public synchronized void setIndexedWriteMethod(Method writeMethod)
throws IntrospectionException {
// If the indexed property type has not been set, then set it.
Class<?> type = findIndexedPropertyType(getIndexedReadMethod(),
writeMethod);
setIndexedPropertyType(type);
setIndexedWriteMethod0(writeMethod);
}
private void setIndexedWriteMethod0(Method writeMethod) {
this.indexedWriteMethodRef.set(writeMethod);
if (writeMethod == null) {
indexedWriteMethodName = null;
return;
}
setClass0(writeMethod.getDeclaringClass());
indexedWriteMethodName = writeMethod.getName();
setTransient(writeMethod.getAnnotation(Transient.class));
}
/**
* Returns the Java type info for the indexed property.
* Note that the {@code Class} object may describe
* primitive Java types such as {@code int}.
* This type is returned by the indexed read method
* or is used as the parameter type of the indexed write method.
*
* @return the {@code Class} object that represents the Java type info,
* or {@code null} if the type cannot be determined
*/
public synchronized Class<?> getIndexedPropertyType() {
Class<?> type = getIndexedPropertyType0();
if (type == null) {
try {
type = findIndexedPropertyType(getIndexedReadMethod(),
getIndexedWriteMethod());
setIndexedPropertyType(type);
} catch (IntrospectionException ex) {
// fall
}
}
return type;
}
// Private methods which set get/set the Reference objects
private void setIndexedPropertyType(Class<?> type) {
this.indexedPropertyTypeRef = getWeakReference(type);
}
private Class<?> getIndexedPropertyType0() {
return (this.indexedPropertyTypeRef != null)
? this.indexedPropertyTypeRef.get()
: null;
}
private Class<?> findIndexedPropertyType(Method indexedReadMethod,
Method indexedWriteMethod)
throws IntrospectionException {
Class<?> indexedPropertyType = null;
if (indexedReadMethod != null) {
Class params[] = getParameterTypes(getClass0(), indexedReadMethod);
if (params.length != 1) {
throw new IntrospectionException("bad indexed read method arg count");
}
if (params[0] != Integer.TYPE) {
throw new IntrospectionException("non int index to indexed read method");
}
indexedPropertyType = getReturnType(getClass0(), indexedReadMethod);
if (indexedPropertyType == Void.TYPE) {
throw new IntrospectionException("indexed read method returns void");
}
}
if (indexedWriteMethod != null) {
Class params[] = getParameterTypes(getClass0(), indexedWriteMethod);
if (params.length != 2) {
throw new IntrospectionException("bad indexed write method arg count");
}
if (params[0] != Integer.TYPE) {
throw new IntrospectionException("non int index to indexed write method");
}
if (indexedPropertyType == null || params[1].isAssignableFrom(indexedPropertyType)) {
indexedPropertyType = params[1];
} else if (!indexedPropertyType.isAssignableFrom(params[1])) {
throw new IntrospectionException(
"type mismatch between indexed read and indexed write methods: "
+ getName());
}
}
Class<?> propertyType = getPropertyType();
if (propertyType != null && (!propertyType.isArray() ||
propertyType.getComponentType() != indexedPropertyType)) {
throw new IntrospectionException("type mismatch between indexed and non-indexed methods: "
+ getName());
}
return indexedPropertyType;
}
/**
* Compares this <code>PropertyDescriptor</code> against the specified object.
* Returns true if the objects are the same. Two <code>PropertyDescriptor</code>s
* are the same if the read, write, property types, property editor and
* flags are equivalent.
*
* @since 1.4
*/
public boolean equals(Object obj) {
// Note: This would be identical to PropertyDescriptor but they don't
// share the same fields.
if (this == obj) {
return true;
}
if (obj != null && obj instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor other = (IndexedPropertyDescriptor)obj;
Method otherIndexedReadMethod = other.getIndexedReadMethod();
Method otherIndexedWriteMethod = other.getIndexedWriteMethod();
if (!compareMethods(getIndexedReadMethod(), otherIndexedReadMethod)) {
return false;
}
if (!compareMethods(getIndexedWriteMethod(), otherIndexedWriteMethod)) {
return false;
}
if (getIndexedPropertyType() != other.getIndexedPropertyType()) {
return false;
}
return super.equals(obj);
}
return false;
}
/**
* Package-private constructor.
* Merge two property descriptors. Where they conflict, give the
* second argument (y) priority over the first argument (x).
*
* @param x The first (lower priority) PropertyDescriptor
* @param y The second (higher priority) PropertyDescriptor
*/
IndexedPropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
super(x,y);
Method tr = null;
Method tw = null;
if (x instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor ix = (IndexedPropertyDescriptor) x;
tr = ix.getIndexedReadMethod();
tw = ix.getIndexedWriteMethod();
}
if (y instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor iy = (IndexedPropertyDescriptor) y;
Method yr = iy.getIndexedReadMethod();
if (isAssignable(tr, yr)) {
tr = yr;
}
Method yw = iy.getIndexedWriteMethod();
if (isAssignable(tw, yw)) {
tw = yw;
}
}
try {
if(tr != null) {
setIndexedReadMethod(tr);
}
if(tw != null) {
setIndexedWriteMethod(tw);
}
} catch(IntrospectionException ex) {
// Should not happen
throw new AssertionError(ex);
}
}
/*
* Package-private dup constructor
* This must isolate the new object from any changes to the old object.
*/
IndexedPropertyDescriptor(IndexedPropertyDescriptor old) {
super(old);
this.indexedReadMethodRef.set(old.indexedReadMethodRef.get());
this.indexedWriteMethodRef.set(old.indexedWriteMethodRef.get());
indexedPropertyTypeRef = old.indexedPropertyTypeRef;
indexedWriteMethodName = old.indexedWriteMethodName;
indexedReadMethodName = old.indexedReadMethodName;
}
void updateGenericsFor(Class<?> type) {
super.updateGenericsFor(type);
try {
setIndexedPropertyType(findIndexedPropertyType(this.indexedReadMethodRef.get(), this.indexedWriteMethodRef.get()));
}
catch (IntrospectionException exception) {
setIndexedPropertyType(null);
}
}
/**
* Returns a hash code value for the object.
* See {@link java.lang.Object#hashCode} for a complete description.
*
* @return a hash code value for this object.
* @since 1.5
*/
public int hashCode() {
int result = super.hashCode();
result = 37 * result + ((indexedWriteMethodName == null) ? 0 :
indexedWriteMethodName.hashCode());
result = 37 * result + ((indexedReadMethodName == null) ? 0 :
indexedReadMethodName.hashCode());
result = 37 * result + ((getIndexedPropertyType() == null) ? 0 :
getIndexedPropertyType().hashCode());
return result;
}
void appendTo(StringBuilder sb) {
super.appendTo(sb);
appendTo(sb, "indexedPropertyType", this.indexedPropertyTypeRef);
appendTo(sb, "indexedReadMethod", this.indexedReadMethodRef.get());
appendTo(sb, "indexedWriteMethod", this.indexedWriteMethodRef.get());
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 1996, 2009, 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;
/**
* Thrown when an exception happens during Introspection.
* <p>
* Typical causes include not being able to map a string class name
* to a Class object, not being able to resolve a string method name,
* or specifying a method name that has the wrong type signature for
* its intended use.
*/
public
class IntrospectionException extends Exception {
private static final long serialVersionUID = -3728150539969542619L;
/**
* Constructs an <code>IntrospectionException</code> with a
* detailed message.
*
* @param mess Descriptive message
*/
public IntrospectionException(String mess) {
super(mess);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 1996, 2013, 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 java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.List;
import java.util.ArrayList;
/**
* A MethodDescriptor describes a particular method that a Java Bean
* supports for external access from other components.
*/
public class MethodDescriptor extends FeatureDescriptor {
private final MethodRef methodRef = new MethodRef();
private String[] paramNames;
private List<WeakReference<Class<?>>> params;
private ParameterDescriptor parameterDescriptors[];
/**
* Constructs a <code>MethodDescriptor</code> from a
* <code>Method</code>.
*
* @param method The low-level method information.
*/
public MethodDescriptor(Method method) {
this(method, null);
}
/**
* Constructs a <code>MethodDescriptor</code> from a
* <code>Method</code> providing descriptive information for each
* of the method's parameters.
*
* @param method The low-level method information.
* @param parameterDescriptors Descriptive information for each of the
* method's parameters.
*/
public MethodDescriptor(Method method,
ParameterDescriptor parameterDescriptors[]) {
setName(method.getName());
setMethod(method);
this.parameterDescriptors = (parameterDescriptors != null)
? parameterDescriptors.clone()
: null;
}
/**
* Gets the method that this MethodDescriptor encapsulates.
*
* @return The low-level description of the method
*/
public synchronized Method getMethod() {
Method method = this.methodRef.get();
if (method == null) {
Class<?> cls = getClass0();
String name = getName();
if ((cls != null) && (name != null)) {
Class<?>[] params = getParams();
if (params == null) {
for (int i = 0; i < 3; i++) {
// Find methods for up to 2 params. We are guessing here.
// This block should never execute unless the classloader
// that loaded the argument classes disappears.
method = Introspector.findMethod(cls, name, i, null);
if (method != null) {
break;
}
}
} else {
method = Introspector.findMethod(cls, name, params.length, params);
}
setMethod(method);
}
}
return method;
}
private synchronized void setMethod(Method method) {
if (method == null) {
return;
}
if (getClass0() == null) {
setClass0(method.getDeclaringClass());
}
setParams(getParameterTypes(getClass0(), method));
this.methodRef.set(method);
}
private synchronized void setParams(Class<?>[] param) {
if (param == null) {
return;
}
paramNames = new String[param.length];
params = new ArrayList<>(param.length);
for (int i = 0; i < param.length; i++) {
paramNames[i] = param[i].getName();
params.add(new WeakReference<Class<?>>(param[i]));
}
}
// pp getParamNames used as an optimization to avoid method.getParameterTypes.
String[] getParamNames() {
return paramNames;
}
private synchronized Class<?>[] getParams() {
Class<?>[] clss = new Class<?>[params.size()];
for (int i = 0; i < params.size(); i++) {
Reference<? extends Class<?>> ref = (Reference<? extends Class<?>>)params.get(i);
Class<?> cls = ref.get();
if (cls == null) {
return null;
} else {
clss[i] = cls;
}
}
return clss;
}
/**
* Gets the ParameterDescriptor for each of this MethodDescriptor's
* method's parameters.
*
* @return The locale-independent names of the parameters. May return
* a null array if the parameter names aren't known.
*/
public ParameterDescriptor[] getParameterDescriptors() {
return (this.parameterDescriptors != null)
? this.parameterDescriptors.clone()
: null;
}
private static Method resolve(Method oldMethod, Method newMethod) {
if (oldMethod == null) {
return newMethod;
}
if (newMethod == null) {
return oldMethod;
}
return !oldMethod.isSynthetic() && newMethod.isSynthetic() ? oldMethod : newMethod;
}
/*
* Package-private constructor
* Merge two method descriptors. Where they conflict, give the
* second argument (y) priority over the first argument (x).
* @param x The first (lower priority) MethodDescriptor
* @param y The second (higher priority) MethodDescriptor
*/
MethodDescriptor(MethodDescriptor x, MethodDescriptor y) {
super(x, y);
this.methodRef.set(resolve(x.methodRef.get(), y.methodRef.get()));
params = x.params;
if (y.params != null) {
params = y.params;
}
paramNames = x.paramNames;
if (y.paramNames != null) {
paramNames = y.paramNames;
}
parameterDescriptors = x.parameterDescriptors;
if (y.parameterDescriptors != null) {
parameterDescriptors = y.parameterDescriptors;
}
}
/*
* Package-private dup constructor
* This must isolate the new object from any changes to the old object.
*/
MethodDescriptor(MethodDescriptor old) {
super(old);
this.methodRef.set(old.getMethod());
params = old.params;
paramNames = old.paramNames;
if (old.parameterDescriptors != null) {
int len = old.parameterDescriptors.length;
parameterDescriptors = new ParameterDescriptor[len];
for (int i = 0; i < len ; i++) {
parameterDescriptors[i] = new ParameterDescriptor(old.parameterDescriptors[i]);
}
}
}
void appendTo(StringBuilder sb) {
appendTo(sb, "method", this.methodRef.get());
if (this.parameterDescriptors != null) {
sb.append("; parameterDescriptors={");
for (ParameterDescriptor pd : this.parameterDescriptors) {
sb.append(pd).append(", ");
}
sb.setLength(sb.length() - 2);
sb.append("}");
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2013, 2016, 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 java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import static sun.reflect.misc.ReflectUtil.isPackageAccessible;
final class MethodRef {
private String signature;
private SoftReference<Method> methodRef;
private WeakReference<Class<?>> typeRef;
void set(Method method) {
if (method == null) {
this.signature = null;
this.methodRef = null;
this.typeRef = null;
}
else {
this.signature = method.toGenericString();
this.methodRef = new SoftReference<>(method);
this.typeRef = new WeakReference<Class<?>>(method.getDeclaringClass());
}
}
boolean isSet() {
return this.methodRef != null;
}
Method get() {
if (this.methodRef == null) {
return null;
}
Method method = this.methodRef.get();
if (method == null) {
method = find(this.typeRef.get(), this.signature);
if (method == null) {
this.signature = null;
this.methodRef = null;
this.typeRef = null;
return null;
}
this.methodRef = new SoftReference<>(method);
}
return isPackageAccessible(method.getDeclaringClass()) ? method : null;
}
private static Method find(Class<?> type, String signature) {
if (type != null) {
for (Method method : type.getMethods()) {
if (type.equals(method.getDeclaringClass())) {
if (method.toGenericString().equals(signature)) {
return method;
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2000, 2011, 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 java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import static java.util.Locale.ENGLISH;
/**
* A utility class which generates unique names for object instances.
* The name will be a concatenation of the unqualified class name
* and an instance number.
* <p>
* For example, if the first object instance javax.swing.JButton
* is passed into <code>instanceName</code> then the returned
* string identifier will be &quot;JButton0&quot;.
*
* @author Philip Milne
*/
class NameGenerator {
private Map<Object, String> valueToName;
private Map<String, Integer> nameToCount;
public NameGenerator() {
valueToName = new IdentityHashMap<>();
nameToCount = new HashMap<>();
}
/**
* Clears the name cache. Should be called to near the end of
* the encoding cycle.
*/
public void clear() {
valueToName.clear();
nameToCount.clear();
}
/**
* Returns the root name of the class.
*/
@SuppressWarnings("rawtypes")
public static String unqualifiedClassName(Class type) {
if (type.isArray()) {
return unqualifiedClassName(type.getComponentType())+"Array";
}
String name = type.getName();
return name.substring(name.lastIndexOf('.')+1);
}
/**
* Returns a String which capitalizes the first letter of the string.
*/
public static String capitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
}
/**
* Returns a unique string which identifies the object instance.
* Invocations are cached so that if an object has been previously
* passed into this method then the same identifier is returned.
*
* @param instance object used to generate string
* @return a unique string representing the object
*/
public String instanceName(Object instance) {
if (instance == null) {
return "null";
}
if (instance instanceof Class) {
return unqualifiedClassName((Class)instance);
}
else {
String result = valueToName.get(instance);
if (result != null) {
return result;
}
Class<?> type = instance.getClass();
String className = unqualifiedClassName(type);
Integer size = nameToCount.get(className);
int instanceNumber = (size == null) ? 0 : (size).intValue() + 1;
nameToCount.put(className, new Integer(instanceNumber));
result = className + instanceNumber;
valueToName.put(instance, result);
return result;
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 1996, 1997, 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;
/**
* The ParameterDescriptor class allows bean implementors to provide
* additional information on each of their parameters, beyond the
* low level type information provided by the java.lang.reflect.Method
* class.
* <p>
* Currently all our state comes from the FeatureDescriptor base class.
*/
public class ParameterDescriptor extends FeatureDescriptor {
/**
* Public default constructor.
*/
public ParameterDescriptor() {
}
/**
* Package private dup constructor.
* This must isolate the new object from any changes to the old object.
*/
ParameterDescriptor(ParameterDescriptor old) {
super(old);
}
}

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2000, 2013, 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;
/**
* The PersistenceDelegate class takes the responsibility
* for expressing the state of an instance of a given class
* in terms of the methods in the class's public API. Instead
* of associating the responsibility of persistence with
* the class itself as is done, for example, by the
* <code>readObject</code> and <code>writeObject</code>
* methods used by the <code>ObjectOutputStream</code>, streams like
* the <code>XMLEncoder</code> which
* use this delegation model can have their behavior controlled
* independently of the classes themselves. Normally, the class
* is the best place to put such information and conventions
* can easily be expressed in this delegation scheme to do just that.
* Sometimes however, it is the case that a minor problem
* in a single class prevents an entire object graph from
* being written and this can leave the application
* developer with no recourse but to attempt to shadow
* the problematic classes locally or use alternative
* persistence techniques. In situations like these, the
* delegation model gives a relatively clean mechanism for
* the application developer to intervene in all parts of the
* serialization process without requiring that modifications
* be made to the implementation of classes which are not part
* of the application itself.
* <p>
* In addition to using a delegation model, this persistence
* scheme differs from traditional serialization schemes
* in requiring an analog of the <code>writeObject</code>
* method without a corresponding <code>readObject</code>
* method. The <code>writeObject</code> analog encodes each
* instance in terms of its public API and there is no need to
* define a <code>readObject</code> analog
* since the procedure for reading the serialized form
* is defined by the semantics of method invocation as laid
* out in the Java Language Specification.
* Breaking the dependency between <code>writeObject</code>
* and <code>readObject</code> implementations, which may
* change from version to version, is the key factor
* in making the archives produced by this technique immune
* to changes in the private implementations of the classes
* to which they refer.
* <p>
* A persistence delegate, may take control of all
* aspects of the persistence of an object including:
* <ul>
* <li>
* Deciding whether or not an instance can be mutated
* into another instance of the same class.
* <li>
* Instantiating the object, either by calling a
* public constructor or a public factory method.
* <li>
* Performing the initialization of the object.
* </ul>
* @see XMLEncoder
*
* @since 1.4
*
* @author Philip Milne
*/
public abstract class PersistenceDelegate {
/**
* The <code>writeObject</code> is a single entry point to the persistence
* and is used by a <code>Encoder</code> in the traditional
* mode of delegation. Although this method is not final,
* it should not need to be subclassed under normal circumstances.
* <p>
* This implementation first checks to see if the stream
* has already encountered this object. Next the
* <code>mutatesTo</code> method is called to see if
* that candidate returned from the stream can
* be mutated into an accurate copy of <code>oldInstance</code>.
* If it can, the <code>initialize</code> method is called to
* perform the initialization. If not, the candidate is removed
* from the stream, and the <code>instantiate</code> method
* is called to create a new candidate for this object.
*
* @param oldInstance The instance that will be created by this expression.
* @param out The stream to which this expression will be written.
*
* @throws NullPointerException if {@code out} is {@code null}
*/
public void writeObject(Object oldInstance, Encoder out) {
Object newInstance = out.get(oldInstance);
if (!mutatesTo(oldInstance, newInstance)) {
out.remove(oldInstance);
out.writeExpression(instantiate(oldInstance, out));
}
else {
initialize(oldInstance.getClass(), oldInstance, newInstance, out);
}
}
/**
* Returns true if an <em>equivalent</em> copy of <code>oldInstance</code> may be
* created by applying a series of statements to <code>newInstance</code>.
* In the specification of this method, we mean by equivalent that the modified instance
* is indistinguishable from <code>oldInstance</code> in the behavior
* of the relevant methods in its public API. [Note: we use the
* phrase <em>relevant</em> methods rather than <em>all</em> methods
* here only because, to be strictly correct, methods like <code>hashCode</code>
* and <code>toString</code> prevent most classes from producing truly
* indistinguishable copies of their instances].
* <p>
* The default behavior returns <code>true</code>
* if the classes of the two instances are the same.
*
* @param oldInstance The instance to be copied.
* @param newInstance The instance that is to be modified.
* @return True if an equivalent copy of <code>newInstance</code> may be
* created by applying a series of mutations to <code>oldInstance</code>.
*/
protected boolean mutatesTo(Object oldInstance, Object newInstance) {
return (newInstance != null && oldInstance != null &&
oldInstance.getClass() == newInstance.getClass());
}
/**
* Returns an expression whose value is <code>oldInstance</code>.
* This method is used to characterize the constructor
* or factory method that should be used to create the given object.
* For example, the <code>instantiate</code> method of the persistence
* delegate for the <code>Field</code> class could be defined as follows:
* <pre>
* Field f = (Field)oldInstance;
* return new Expression(f, f.getDeclaringClass(), "getField", new Object[]{f.getName()});
* </pre>
* Note that we declare the value of the returned expression so that
* the value of the expression (as returned by <code>getValue</code>)
* will be identical to <code>oldInstance</code>.
*
* @param oldInstance The instance that will be created by this expression.
* @param out The stream to which this expression will be written.
* @return An expression whose value is <code>oldInstance</code>.
*
* @throws NullPointerException if {@code out} is {@code null}
* and this value is used in the method
*/
protected abstract Expression instantiate(Object oldInstance, Encoder out);
/**
* Produce a series of statements with side effects on <code>newInstance</code>
* so that the new instance becomes <em>equivalent</em> to <code>oldInstance</code>.
* In the specification of this method, we mean by equivalent that, after the method
* returns, the modified instance is indistinguishable from
* <code>newInstance</code> in the behavior of all methods in its
* public API.
* <p>
* The implementation typically achieves this goal by producing a series of
* "what happened" statements involving the <code>oldInstance</code>
* and its publicly available state. These statements are sent
* to the output stream using its <code>writeExpression</code>
* method which returns an expression involving elements in
* a cloned environment simulating the state of an input stream during
* reading. Each statement returned will have had all instances
* the old environment replaced with objects which exist in the new
* one. In particular, references to the target of these statements,
* which start out as references to <code>oldInstance</code> are returned
* as references to the <code>newInstance</code> instead.
* Executing these statements effects an incremental
* alignment of the state of the two objects as a series of
* modifications to the objects in the new environment.
* By the time the initialize method returns it should be impossible
* to tell the two instances apart by using their public APIs.
* Most importantly, the sequence of steps that were used to make
* these objects appear equivalent will have been recorded
* by the output stream and will form the actual output when
* the stream is flushed.
* <p>
* The default implementation, calls the <code>initialize</code>
* method of the type's superclass.
*
* @param type the type of the instances
* @param oldInstance The instance to be copied.
* @param newInstance The instance that is to be modified.
* @param out The stream to which any initialization statements should be written.
*
* @throws NullPointerException if {@code out} is {@code null}
*/
protected void initialize(Class<?> type,
Object oldInstance, Object newInstance,
Encoder out)
{
Class<?> superType = type.getSuperclass();
PersistenceDelegate info = out.getPersistenceDelegate(superType);
info.initialize(superType, oldInstance, newInstance, out);
}
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 1996, 2011, 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 java.util.EventObject;
/**
* A "PropertyChange" event gets delivered whenever a bean changes a "bound"
* or "constrained" property. A PropertyChangeEvent object is sent as an
* argument to the PropertyChangeListener and VetoableChangeListener methods.
* <P>
* Normally PropertyChangeEvents are accompanied by the name and the old
* and new value of the changed property. If the new value is a primitive
* type (such as int or boolean) it must be wrapped as the
* corresponding java.lang.* Object type (such as Integer or Boolean).
* <P>
* Null values may be provided for the old and the new values if their
* true values are not known.
* <P>
* An event source may send a null object as the name to indicate that an
* arbitrary set of if its properties have changed. In this case the
* old and new values should also be null.
*/
public class PropertyChangeEvent extends EventObject {
private static final long serialVersionUID = 7042693688939648123L;
/**
* Constructs a new {@code PropertyChangeEvent}.
*
* @param source the bean that fired the event
* @param propertyName the programmatic name of the property that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
*
* @throws IllegalArgumentException if {@code source} is {@code null}
*/
public PropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue) {
super(source);
this.propertyName = propertyName;
this.newValue = newValue;
this.oldValue = oldValue;
}
/**
* Gets the programmatic name of the property that was changed.
*
* @return The programmatic name of the property that was changed.
* May be null if multiple properties have changed.
*/
public String getPropertyName() {
return propertyName;
}
/**
* Gets the new value for the property, expressed as an Object.
*
* @return The new value for the property, expressed as an Object.
* May be null if multiple properties have changed.
*/
public Object getNewValue() {
return newValue;
}
/**
* Gets the old value for the property, expressed as an Object.
*
* @return The old value for the property, expressed as an Object.
* May be null if multiple properties have changed.
*/
public Object getOldValue() {
return oldValue;
}
/**
* Sets the propagationId object for the event.
*
* @param propagationId The propagationId object for the event.
*/
public void setPropagationId(Object propagationId) {
this.propagationId = propagationId;
}
/**
* The "propagationId" field is reserved for future use. In Beans 1.0
* the sole requirement is that if a listener catches a PropertyChangeEvent
* and then fires a PropertyChangeEvent of its own, then it should
* make sure that it propagates the propagationId field from its
* incoming event to its outgoing event.
*
* @return the propagationId object associated with a bound/constrained
* property update.
*/
public Object getPropagationId() {
return propagationId;
}
/**
* name of the property that changed. May be null, if not known.
* @serial
*/
private String propertyName;
/**
* New value for property. May be null if not known.
* @serial
*/
private Object newValue;
/**
* Previous value for property. May be null if not known.
* @serial
*/
private Object oldValue;
/**
* Propagation ID. May be null.
* @serial
* @see #getPropagationId
*/
private Object propagationId;
/**
* 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("[propertyName=").append(getPropertyName());
appendTo(sb);
sb.append("; oldValue=").append(getOldValue());
sb.append("; newValue=").append(getNewValue());
sb.append("; propagationId=").append(getPropagationId());
sb.append("; source=").append(getSource());
return sb.append("]").toString();
}
void appendTo(StringBuilder sb) {
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 1996, 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;
/**
* A "PropertyChange" event gets fired whenever a bean changes a "bound"
* property. You can register a PropertyChangeListener with a source
* bean so as to be notified of any bound property updates.
*/
public interface PropertyChangeListener extends java.util.EventListener {
/**
* This method gets called when a bound property is changed.
* @param evt A PropertyChangeEvent object describing the event source
* and the property that has changed.
*/
void propertyChange(PropertyChangeEvent evt);
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2000, 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 java.util.EventListenerProxy;
/**
* A class which extends the {@code EventListenerProxy}
* specifically for adding a {@code PropertyChangeListener}
* with a "bound" property.
* Instances of this class can be added
* as {@code PropertyChangeListener}s to a bean
* which supports firing property change events.
* <p>
* If the object has a {@code getPropertyChangeListeners} method
* then the array returned could be a mixture of {@code PropertyChangeListener}
* and {@code PropertyChangeListenerProxy} objects.
*
* @see java.util.EventListenerProxy
* @see PropertyChangeSupport#getPropertyChangeListeners
* @since 1.4
*/
public class PropertyChangeListenerProxy
extends EventListenerProxy<PropertyChangeListener>
implements PropertyChangeListener {
private final String propertyName;
/**
* Constructor which binds the {@code PropertyChangeListener}
* to a specific property.
*
* @param propertyName the name of the property to listen on
* @param listener the listener object
*/
public PropertyChangeListenerProxy(String propertyName, PropertyChangeListener listener) {
super(listener);
this.propertyName = propertyName;
}
/**
* Forwards the property change event to the listener delegate.
*
* @param event the property change event
*/
public void propertyChange(PropertyChangeEvent event) {
getListener().propertyChange(event);
}
/**
* Returns the name of the named property associated with the listener.
*
* @return the name of the named property associated with the listener
*/
public String getPropertyName() {
return this.propertyName;
}
}

View File

@@ -0,0 +1,547 @@
/*
* Copyright (c) 1996, 2013, 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 java.io.Serializable;
import java.io.ObjectStreamField;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map.Entry;
/**
* This is a utility class that can be used by beans that support bound
* properties. It manages a list of listeners and dispatches
* {@link PropertyChangeEvent}s to them. You can use an instance of this class
* as a member field of your bean and delegate these types of work to it.
* The {@link PropertyChangeListener} can be registered for all properties
* or for a property specified by name.
* <p>
* Here is an example of {@code PropertyChangeSupport} usage that follows
* the rules and recommendations laid out in the JavaBeans&trade; specification:
* <pre>
* public class MyBean {
* private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
*
* public void addPropertyChangeListener(PropertyChangeListener listener) {
* this.pcs.addPropertyChangeListener(listener);
* }
*
* public void removePropertyChangeListener(PropertyChangeListener listener) {
* this.pcs.removePropertyChangeListener(listener);
* }
*
* private String value;
*
* public String getValue() {
* return this.value;
* }
*
* public void setValue(String newValue) {
* String oldValue = this.value;
* this.value = newValue;
* this.pcs.firePropertyChange("value", oldValue, newValue);
* }
*
* [...]
* }
* </pre>
* <p>
* A {@code PropertyChangeSupport} instance is thread-safe.
* <p>
* This class is serializable. When it is serialized it will save
* (and restore) any listeners that are themselves serializable. Any
* non-serializable listeners will be skipped during serialization.
*
* @see VetoableChangeSupport
*/
public class PropertyChangeSupport implements Serializable {
private PropertyChangeListenerMap map = new PropertyChangeListenerMap();
/**
* Constructs a <code>PropertyChangeSupport</code> object.
*
* @param sourceBean The bean to be given as the source for any events.
*/
public PropertyChangeSupport(Object sourceBean) {
if (sourceBean == null) {
throw new NullPointerException();
}
source = sourceBean;
}
/**
* Add a PropertyChangeListener to the listener list.
* The listener is registered for all properties.
* The same listener object may be added more than once, and will be called
* as many times as it is added.
* If <code>listener</code> is null, no exception is thrown and no action
* is taken.
*
* @param listener The PropertyChangeListener to be added
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (listener == null) {
return;
}
if (listener instanceof PropertyChangeListenerProxy) {
PropertyChangeListenerProxy proxy =
(PropertyChangeListenerProxy)listener;
// Call two argument add method.
addPropertyChangeListener(proxy.getPropertyName(),
proxy.getListener());
} else {
this.map.add(null, listener);
}
}
/**
* Remove a PropertyChangeListener from the listener list.
* This removes a PropertyChangeListener that was registered
* for all properties.
* If <code>listener</code> was added more than once to the same event
* source, it will be notified one less time after being removed.
* If <code>listener</code> is null, or was never added, no exception is
* thrown and no action is taken.
*
* @param listener The PropertyChangeListener to be removed
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (listener == null) {
return;
}
if (listener instanceof PropertyChangeListenerProxy) {
PropertyChangeListenerProxy proxy =
(PropertyChangeListenerProxy)listener;
// Call two argument remove method.
removePropertyChangeListener(proxy.getPropertyName(),
proxy.getListener());
} else {
this.map.remove(null, listener);
}
}
/**
* Returns an array of all the listeners that were added to the
* PropertyChangeSupport object with addPropertyChangeListener().
* <p>
* If some listeners have been added with a named property, then
* the returned array will be a mixture of PropertyChangeListeners
* and <code>PropertyChangeListenerProxy</code>s. If the calling
* method is interested in distinguishing the listeners then it must
* test each element to see if it's a
* <code>PropertyChangeListenerProxy</code>, perform the cast, and examine
* the parameter.
*
* <pre>{@code
* PropertyChangeListener[] listeners = bean.getPropertyChangeListeners();
* for (int i = 0; i < listeners.length; i++) {
* if (listeners[i] instanceof PropertyChangeListenerProxy) {
* PropertyChangeListenerProxy proxy =
* (PropertyChangeListenerProxy)listeners[i];
* if (proxy.getPropertyName().equals("foo")) {
* // proxy is a PropertyChangeListener which was associated
* // with the property named "foo"
* }
* }
* }
* }</pre>
*
* @see PropertyChangeListenerProxy
* @return all of the <code>PropertyChangeListeners</code> added or an
* empty array if no listeners have been added
* @since 1.4
*/
public PropertyChangeListener[] getPropertyChangeListeners() {
return this.map.getListeners();
}
/**
* Add a PropertyChangeListener for a specific property. The listener
* will be invoked only when a call on firePropertyChange names that
* specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>propertyName</code> or <code>listener</code> is null, no
* exception is thrown and no action is taken.
*
* @param propertyName The name of the property to listen on.
* @param listener The PropertyChangeListener to be added
*/
public void addPropertyChangeListener(
String propertyName,
PropertyChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
listener = this.map.extract(listener);
if (listener != null) {
this.map.add(propertyName, listener);
}
}
/**
* Remove a PropertyChangeListener for a specific property.
* If <code>listener</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>propertyName</code> is null, no exception is thrown and no
* action is taken.
* If <code>listener</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param propertyName The name of the property that was listened on.
* @param listener The PropertyChangeListener to be removed
*/
public void removePropertyChangeListener(
String propertyName,
PropertyChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
listener = this.map.extract(listener);
if (listener != null) {
this.map.remove(propertyName, listener);
}
}
/**
* Returns an array of all the listeners which have been associated
* with the named property.
*
* @param propertyName The name of the property being listened to
* @return all of the <code>PropertyChangeListeners</code> associated with
* the named property. If no such listeners have been added,
* or if <code>propertyName</code> is null, an empty array is
* returned.
* @since 1.4
*/
public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
return this.map.getListeners(propertyName);
}
/**
* Reports a bound property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if old and new values are equal and non-null.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #firePropertyChange(PropertyChangeEvent)} method.
*
* @param propertyName the programmatic name of the property that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
*/
public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
}
}
/**
* Reports an integer bound property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if old and new values are equal.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #firePropertyChange(String, Object, Object)} method.
*
* @param propertyName the programmatic name of the property that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
*/
public void firePropertyChange(String propertyName, int oldValue, int newValue) {
if (oldValue != newValue) {
firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
}
}
/**
* Reports a boolean bound property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if old and new values are equal.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #firePropertyChange(String, Object, Object)} method.
*
* @param propertyName the programmatic name of the property that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
*/
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
if (oldValue != newValue) {
firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
}
}
/**
* Fires a property change event to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if the given event's old and new values are equal and non-null.
*
* @param event the {@code PropertyChangeEvent} to be fired
*/
public void firePropertyChange(PropertyChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
String name = event.getPropertyName();
PropertyChangeListener[] common = this.map.get(null);
PropertyChangeListener[] named = (name != null)
? this.map.get(name)
: null;
fire(common, event);
fire(named, event);
}
}
private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {
if (listeners != null) {
for (PropertyChangeListener listener : listeners) {
listener.propertyChange(event);
}
}
}
/**
* Reports a bound indexed property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if old and new values are equal and non-null.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #firePropertyChange(PropertyChangeEvent)} method.
*
* @param propertyName the programmatic name of the property that was changed
* @param index the index of the property element that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
* @since 1.5
*/
public void fireIndexedPropertyChange(String propertyName, int index, Object oldValue, Object newValue) {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
firePropertyChange(new IndexedPropertyChangeEvent(source, propertyName, oldValue, newValue, index));
}
}
/**
* Reports an integer bound indexed property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if old and new values are equal.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #fireIndexedPropertyChange(String, int, Object, Object)} method.
*
* @param propertyName the programmatic name of the property that was changed
* @param index the index of the property element that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
* @since 1.5
*/
public void fireIndexedPropertyChange(String propertyName, int index, int oldValue, int newValue) {
if (oldValue != newValue) {
fireIndexedPropertyChange(propertyName, index, Integer.valueOf(oldValue), Integer.valueOf(newValue));
}
}
/**
* Reports a boolean bound indexed property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* No event is fired if old and new values are equal.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #fireIndexedPropertyChange(String, int, Object, Object)} method.
*
* @param propertyName the programmatic name of the property that was changed
* @param index the index of the property element that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
* @since 1.5
*/
public void fireIndexedPropertyChange(String propertyName, int index, boolean oldValue, boolean newValue) {
if (oldValue != newValue) {
fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
}
}
/**
* Check if there are any listeners for a specific property, including
* those registered on all properties. If <code>propertyName</code>
* is null, only check for listeners registered on all properties.
*
* @param propertyName the property name.
* @return true if there are one or more listeners for the given property
*/
public boolean hasListeners(String propertyName) {
return this.map.hasListeners(propertyName);
}
/**
* @serialData Null terminated list of <code>PropertyChangeListeners</code>.
* <p>
* At serialization time we skip non-serializable listeners and
* only serialize the serializable listeners.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
Hashtable<String, PropertyChangeSupport> children = null;
PropertyChangeListener[] listeners = null;
synchronized (this.map) {
for (Entry<String, PropertyChangeListener[]> entry : this.map.getEntries()) {
String property = entry.getKey();
if (property == null) {
listeners = entry.getValue();
} else {
if (children == null) {
children = new Hashtable<>();
}
PropertyChangeSupport pcs = new PropertyChangeSupport(this.source);
pcs.map.set(null, entry.getValue());
children.put(property, pcs);
}
}
}
ObjectOutputStream.PutField fields = s.putFields();
fields.put("children", children);
fields.put("source", this.source);
fields.put("propertyChangeSupportSerializedDataVersion", 2);
s.writeFields();
if (listeners != null) {
for (PropertyChangeListener l : listeners) {
if (l instanceof Serializable) {
s.writeObject(l);
}
}
}
s.writeObject(null);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
this.map = new PropertyChangeListenerMap();
ObjectInputStream.GetField fields = s.readFields();
@SuppressWarnings("unchecked")
Hashtable<String, PropertyChangeSupport> children = (Hashtable<String, PropertyChangeSupport>) fields.get("children", null);
this.source = fields.get("source", null);
fields.get("propertyChangeSupportSerializedDataVersion", 2);
Object listenerOrNull;
while (null != (listenerOrNull = s.readObject())) {
this.map.add(null, (PropertyChangeListener)listenerOrNull);
}
if (children != null) {
for (Entry<String, PropertyChangeSupport> entry : children.entrySet()) {
for (PropertyChangeListener listener : entry.getValue().getPropertyChangeListeners()) {
this.map.add(entry.getKey(), listener);
}
}
}
}
/**
* The object to be provided as the "source" for any generated events.
*/
private Object source;
/**
* @serialField children Hashtable
* @serialField source Object
* @serialField propertyChangeSupportSerializedDataVersion int
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("children", Hashtable.class),
new ObjectStreamField("source", Object.class),
new ObjectStreamField("propertyChangeSupportSerializedDataVersion", Integer.TYPE)
};
/**
* Serialization version ID, so we're compatible with JDK 1.1
*/
static final long serialVersionUID = 6401253773779951803L;
/**
* This is a {@link ChangeListenerMap ChangeListenerMap} implementation
* that works with {@link PropertyChangeListener PropertyChangeListener} objects.
*/
private static final class PropertyChangeListenerMap extends ChangeListenerMap<PropertyChangeListener> {
private static final PropertyChangeListener[] EMPTY = {};
/**
* Creates an array of {@link PropertyChangeListener PropertyChangeListener} objects.
* This method uses the same instance of the empty array
* when {@code length} equals {@code 0}.
*
* @param length the array length
* @return an array with specified length
*/
@Override
protected PropertyChangeListener[] newArray(int length) {
return (0 < length)
? new PropertyChangeListener[length]
: EMPTY;
}
/**
* Creates a {@link PropertyChangeListenerProxy PropertyChangeListenerProxy}
* object for the specified property.
*
* @param name the name of the property to listen on
* @param listener the listener to process events
* @return a {@code PropertyChangeListenerProxy} object
*/
@Override
protected PropertyChangeListener newProxy(String name, PropertyChangeListener listener) {
return new PropertyChangeListenerProxy(name, listener);
}
/**
* {@inheritDoc}
*/
public final PropertyChangeListener extract(PropertyChangeListener listener) {
while (listener instanceof PropertyChangeListenerProxy) {
listener = ((PropertyChangeListenerProxy) listener).getListener();
}
return listener;
}
}
}

View File

@@ -0,0 +1,750 @@
/*
* Copyright (c) 1996, 2015, 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 java.lang.ref.Reference;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import sun.reflect.misc.ReflectUtil;
/**
* A PropertyDescriptor describes one property that a Java Bean
* exports via a pair of accessor methods.
*/
public class PropertyDescriptor extends FeatureDescriptor {
private Reference<? extends Class<?>> propertyTypeRef;
private final MethodRef readMethodRef = new MethodRef();
private final MethodRef writeMethodRef = new MethodRef();
private Reference<? extends Class<?>> propertyEditorClassRef;
private boolean bound;
private boolean constrained;
// The base name of the method name which will be prefixed with the
// read and write method. If name == "foo" then the baseName is "Foo"
private String baseName;
private String writeMethodName;
private String readMethodName;
/**
* Constructs a PropertyDescriptor for a property that follows
* the standard Java convention by having getFoo and setFoo
* accessor methods. Thus if the argument name is "fred", it will
* assume that the writer method is "setFred" and the reader method
* is "getFred" (or "isFred" for a boolean property). Note that the
* property name should start with a lower case character, which will
* be capitalized in the method names.
*
* @param propertyName The programmatic name of the property.
* @param beanClass The Class object for the target bean. For
* example sun.beans.OurButton.class.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public PropertyDescriptor(String propertyName, Class<?> beanClass)
throws IntrospectionException {
this(propertyName, beanClass,
Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName),
Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));
}
/**
* This constructor takes the name of a simple property, and method
* names for reading and writing the property.
*
* @param propertyName The programmatic name of the property.
* @param beanClass The Class object for the target bean. For
* example sun.beans.OurButton.class.
* @param readMethodName The name of the method used for reading the property
* value. May be null if the property is write-only.
* @param writeMethodName The name of the method used for writing the property
* value. May be null if the property is read-only.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public PropertyDescriptor(String propertyName, Class<?> beanClass,
String readMethodName, String writeMethodName)
throws IntrospectionException {
if (beanClass == null) {
throw new IntrospectionException("Target Bean class is null");
}
if (propertyName == null || propertyName.length() == 0) {
throw new IntrospectionException("bad property name");
}
if ("".equals(readMethodName) || "".equals(writeMethodName)) {
throw new IntrospectionException("read or write method name should not be the empty string");
}
setName(propertyName);
setClass0(beanClass);
this.readMethodName = readMethodName;
if (readMethodName != null && getReadMethod() == null) {
throw new IntrospectionException("Method not found: " + readMethodName);
}
this.writeMethodName = writeMethodName;
if (writeMethodName != null && getWriteMethod() == null) {
throw new IntrospectionException("Method not found: " + writeMethodName);
}
// If this class or one of its base classes allow PropertyChangeListener,
// then we assume that any properties we discover are "bound".
// See Introspector.getTargetPropertyInfo() method.
Class[] args = { PropertyChangeListener.class };
this.bound = null != Introspector.findMethod(beanClass, "addPropertyChangeListener", args.length, args);
}
/**
* This constructor takes the name of a simple property, and Method
* objects for reading and writing the property.
*
* @param propertyName The programmatic name of the property.
* @param readMethod The method used for reading the property value.
* May be null if the property is write-only.
* @param writeMethod The method used for writing the property value.
* May be null if the property is read-only.
* @exception IntrospectionException if an exception occurs during
* introspection.
*/
public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
throws IntrospectionException {
if (propertyName == null || propertyName.length() == 0) {
throw new IntrospectionException("bad property name");
}
setName(propertyName);
setReadMethod(readMethod);
setWriteMethod(writeMethod);
}
/**
* Creates <code>PropertyDescriptor</code> for the specified bean
* with the specified name and methods to read/write the property value.
*
* @param bean the type of the target bean
* @param base the base name of the property (the rest of the method name)
* @param read the method used for reading the property value
* @param write the method used for writing the property value
* @exception IntrospectionException if an exception occurs during introspection
*
* @since 1.7
*/
PropertyDescriptor(Class<?> bean, String base, Method read, Method write) throws IntrospectionException {
if (bean == null) {
throw new IntrospectionException("Target Bean class is null");
}
setClass0(bean);
setName(Introspector.decapitalize(base));
setReadMethod(read);
setWriteMethod(write);
this.baseName = base;
}
/**
* Returns the Java type info for the property.
* Note that the {@code Class} object may describe
* primitive Java types such as {@code int}.
* This type is returned by the read method
* or is used as the parameter type of the write method.
* Returns {@code null} if the type is an indexed property
* that does not support non-indexed access.
*
* @return the {@code Class} object that represents the Java type info,
* or {@code null} if the type cannot be determined
*/
public synchronized Class<?> getPropertyType() {
Class<?> type = getPropertyType0();
if (type == null) {
try {
type = findPropertyType(getReadMethod(), getWriteMethod());
setPropertyType(type);
} catch (IntrospectionException ex) {
// Fall
}
}
return type;
}
private void setPropertyType(Class<?> type) {
this.propertyTypeRef = getWeakReference(type);
}
private Class<?> getPropertyType0() {
return (this.propertyTypeRef != null)
? this.propertyTypeRef.get()
: null;
}
/**
* Gets the method that should be used to read the property value.
*
* @return The method that should be used to read the property value.
* May return null if the property can't be read.
*/
public synchronized Method getReadMethod() {
Method readMethod = this.readMethodRef.get();
if (readMethod == null) {
Class<?> cls = getClass0();
if (cls == null || (readMethodName == null && !this.readMethodRef.isSet())) {
// The read method was explicitly set to null.
return null;
}
String nextMethodName = Introspector.GET_PREFIX + getBaseName();
if (readMethodName == null) {
Class<?> type = getPropertyType0();
if (type == boolean.class || type == null) {
readMethodName = Introspector.IS_PREFIX + getBaseName();
} else {
readMethodName = nextMethodName;
}
}
// Since there can be multiple write methods but only one getter
// method, find the getter method first so that you know what the
// property type is. For booleans, there can be "is" and "get"
// methods. If an "is" method exists, this is the official
// reader method so look for this one first.
readMethod = Introspector.findMethod(cls, readMethodName, 0);
if ((readMethod == null) && !readMethodName.equals(nextMethodName)) {
readMethodName = nextMethodName;
readMethod = Introspector.findMethod(cls, readMethodName, 0);
}
try {
setReadMethod(readMethod);
} catch (IntrospectionException ex) {
// fall
}
}
return readMethod;
}
/**
* Sets the method that should be used to read the property value.
*
* @param readMethod The new read method.
* @throws IntrospectionException if the read method is invalid
*/
public synchronized void setReadMethod(Method readMethod)
throws IntrospectionException {
this.readMethodRef.set(readMethod);
if (readMethod == null) {
readMethodName = null;
return;
}
// The property type is determined by the read method.
setPropertyType(findPropertyType(readMethod, this.writeMethodRef.get()));
setClass0(readMethod.getDeclaringClass());
readMethodName = readMethod.getName();
setTransient(readMethod.getAnnotation(Transient.class));
}
/**
* Gets the method that should be used to write the property value.
*
* @return The method that should be used to write the property value.
* May return null if the property can't be written.
*/
public synchronized Method getWriteMethod() {
Method writeMethod = this.writeMethodRef.get();
if (writeMethod == null) {
Class<?> cls = getClass0();
if (cls == null || (writeMethodName == null && !this.writeMethodRef.isSet())) {
// The write method was explicitly set to null.
return null;
}
// We need the type to fetch the correct method.
Class<?> type = getPropertyType0();
if (type == null) {
try {
// Can't use getPropertyType since it will lead to recursive loop.
type = findPropertyType(getReadMethod(), null);
setPropertyType(type);
} catch (IntrospectionException ex) {
// Without the correct property type we can't be guaranteed
// to find the correct method.
return null;
}
}
if (writeMethodName == null) {
writeMethodName = Introspector.SET_PREFIX + getBaseName();
}
Class<?>[] args = (type == null) ? null : new Class<?>[] { type };
writeMethod = Introspector.findMethod(cls, writeMethodName, 1, args);
if (writeMethod != null) {
if (!writeMethod.getReturnType().equals(void.class)) {
writeMethod = null;
}
}
try {
setWriteMethod(writeMethod);
} catch (IntrospectionException ex) {
// fall through
}
}
return writeMethod;
}
/**
* Sets the method that should be used to write the property value.
*
* @param writeMethod The new write method.
* @throws IntrospectionException if the write method is invalid
*/
public synchronized void setWriteMethod(Method writeMethod)
throws IntrospectionException {
this.writeMethodRef.set(writeMethod);
if (writeMethod == null) {
writeMethodName = null;
return;
}
// Set the property type - which validates the method
setPropertyType(findPropertyType(getReadMethod(), writeMethod));
setClass0(writeMethod.getDeclaringClass());
writeMethodName = writeMethod.getName();
setTransient(writeMethod.getAnnotation(Transient.class));
}
/**
* Overridden to ensure that a super class doesn't take precedent
*/
void setClass0(Class<?> clz) {
if (getClass0() != null && clz.isAssignableFrom(getClass0())) {
// don't replace a subclass with a superclass
return;
}
super.setClass0(clz);
}
/**
* Updates to "bound" properties will cause a "PropertyChange" event to
* get fired when the property is changed.
*
* @return True if this is a bound property.
*/
public boolean isBound() {
return bound;
}
/**
* Updates to "bound" properties will cause a "PropertyChange" event to
* get fired when the property is changed.
*
* @param bound True if this is a bound property.
*/
public void setBound(boolean bound) {
this.bound = bound;
}
/**
* Attempted updates to "Constrained" properties will cause a "VetoableChange"
* event to get fired when the property is changed.
*
* @return True if this is a constrained property.
*/
public boolean isConstrained() {
return constrained;
}
/**
* Attempted updates to "Constrained" properties will cause a "VetoableChange"
* event to get fired when the property is changed.
*
* @param constrained True if this is a constrained property.
*/
public void setConstrained(boolean constrained) {
this.constrained = constrained;
}
/**
* Normally PropertyEditors will be found using the PropertyEditorManager.
* However if for some reason you want to associate a particular
* PropertyEditor with a given property, then you can do it with
* this method.
*
* @param propertyEditorClass The Class for the desired PropertyEditor.
*/
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
this.propertyEditorClassRef = getWeakReference(propertyEditorClass);
}
/**
* Gets any explicit PropertyEditor Class that has been registered
* for this property.
*
* @return Any explicit PropertyEditor Class that has been registered
* for this property. Normally this will return "null",
* indicating that no special editor has been registered,
* so the PropertyEditorManager should be used to locate
* a suitable PropertyEditor.
*/
public Class<?> getPropertyEditorClass() {
return (this.propertyEditorClassRef != null)
? this.propertyEditorClassRef.get()
: null;
}
/**
* Constructs an instance of a property editor using the current
* property editor class.
* <p>
* If the property editor class has a public constructor that takes an
* Object argument then it will be invoked using the bean parameter
* as the argument. Otherwise, the default constructor will be invoked.
*
* @param bean the source object
* @return a property editor instance or null if a property editor has
* not been defined or cannot be created
* @since 1.5
*/
public PropertyEditor createPropertyEditor(Object bean) {
Object editor = null;
final Class<?> cls = getPropertyEditorClass();
if (cls != null && PropertyEditor.class.isAssignableFrom(cls)
&& ReflectUtil.isPackageAccessible(cls)) {
Constructor<?> ctor = null;
if (bean != null) {
try {
ctor = cls.getConstructor(new Class<?>[] { Object.class });
} catch (Exception ex) {
// Fall through
}
}
try {
if (ctor == null) {
editor = cls.newInstance();
} else {
editor = ctor.newInstance(new Object[] { bean });
}
} catch (Exception ex) {
// Fall through
}
}
return (PropertyEditor)editor;
}
/**
* Compares this <code>PropertyDescriptor</code> against the specified object.
* Returns true if the objects are the same. Two <code>PropertyDescriptor</code>s
* are the same if the read, write, property types, property editor and
* flags are equivalent.
*
* @since 1.4
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof PropertyDescriptor) {
PropertyDescriptor other = (PropertyDescriptor)obj;
Method otherReadMethod = other.getReadMethod();
Method otherWriteMethod = other.getWriteMethod();
if (!compareMethods(getReadMethod(), otherReadMethod)) {
return false;
}
if (!compareMethods(getWriteMethod(), otherWriteMethod)) {
return false;
}
if (getPropertyType() == other.getPropertyType() &&
getPropertyEditorClass() == other.getPropertyEditorClass() &&
bound == other.isBound() && constrained == other.isConstrained() &&
writeMethodName == other.writeMethodName &&
readMethodName == other.readMethodName) {
return true;
}
}
return false;
}
/**
* Package private helper method for Descriptor .equals methods.
*
* @param a first method to compare
* @param b second method to compare
* @return boolean to indicate that the methods are equivalent
*/
boolean compareMethods(Method a, Method b) {
// Note: perhaps this should be a protected method in FeatureDescriptor
if ((a == null) != (b == null)) {
return false;
}
if (a != null && b != null) {
if (!a.equals(b)) {
return false;
}
}
return true;
}
/**
* Package-private constructor.
* Merge two property descriptors. Where they conflict, give the
* second argument (y) priority over the first argument (x).
*
* @param x The first (lower priority) PropertyDescriptor
* @param y The second (higher priority) PropertyDescriptor
*/
PropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
super(x,y);
if (y.baseName != null) {
baseName = y.baseName;
} else {
baseName = x.baseName;
}
if (y.readMethodName != null) {
readMethodName = y.readMethodName;
} else {
readMethodName = x.readMethodName;
}
if (y.writeMethodName != null) {
writeMethodName = y.writeMethodName;
} else {
writeMethodName = x.writeMethodName;
}
if (y.propertyTypeRef != null) {
propertyTypeRef = y.propertyTypeRef;
} else {
propertyTypeRef = x.propertyTypeRef;
}
// Figure out the merged read method.
Method xr = x.getReadMethod();
Method yr = y.getReadMethod();
// Normally give priority to y's readMethod.
try {
if (isAssignable(xr, yr)) {
setReadMethod(yr);
} else {
setReadMethod(xr);
}
} catch (IntrospectionException ex) {
// fall through
}
// However, if both x and y reference read methods in the same class,
// give priority to a boolean "is" method over a boolean "get" method.
if (xr != null && yr != null &&
xr.getDeclaringClass() == yr.getDeclaringClass() &&
getReturnType(getClass0(), xr) == boolean.class &&
getReturnType(getClass0(), yr) == boolean.class &&
xr.getName().indexOf(Introspector.IS_PREFIX) == 0 &&
yr.getName().indexOf(Introspector.GET_PREFIX) == 0) {
try {
setReadMethod(xr);
} catch (IntrospectionException ex) {
// fall through
}
}
Method xw = x.getWriteMethod();
Method yw = y.getWriteMethod();
try {
if (yw != null) {
setWriteMethod(yw);
} else {
setWriteMethod(xw);
}
} catch (IntrospectionException ex) {
// Fall through
}
if (y.getPropertyEditorClass() != null) {
setPropertyEditorClass(y.getPropertyEditorClass());
} else {
setPropertyEditorClass(x.getPropertyEditorClass());
}
bound = x.bound | y.bound;
constrained = x.constrained | y.constrained;
}
/*
* Package-private dup constructor.
* This must isolate the new object from any changes to the old object.
*/
PropertyDescriptor(PropertyDescriptor old) {
super(old);
propertyTypeRef = old.propertyTypeRef;
this.readMethodRef.set(old.readMethodRef.get());
this.writeMethodRef.set(old.writeMethodRef.get());
propertyEditorClassRef = old.propertyEditorClassRef;
writeMethodName = old.writeMethodName;
readMethodName = old.readMethodName;
baseName = old.baseName;
bound = old.bound;
constrained = old.constrained;
}
void updateGenericsFor(Class<?> type) {
setClass0(type);
try {
setPropertyType(findPropertyType(this.readMethodRef.get(), this.writeMethodRef.get()));
}
catch (IntrospectionException exception) {
setPropertyType(null);
}
}
/**
* Returns the property type that corresponds to the read and write method.
* The type precedence is given to the readMethod.
*
* @return the type of the property descriptor or null if both
* read and write methods are null.
* @throws IntrospectionException if the read or write method is invalid
*/
private Class<?> findPropertyType(Method readMethod, Method writeMethod)
throws IntrospectionException {
Class<?> propertyType = null;
try {
if (readMethod != null) {
Class<?>[] params = getParameterTypes(getClass0(), readMethod);
if (params.length != 0) {
throw new IntrospectionException("bad read method arg count: "
+ readMethod);
}
propertyType = getReturnType(getClass0(), readMethod);
if (propertyType == Void.TYPE) {
throw new IntrospectionException("read method " +
readMethod.getName() + " returns void");
}
}
if (writeMethod != null) {
Class<?>[] params = getParameterTypes(getClass0(), writeMethod);
if (params.length != 1) {
throw new IntrospectionException("bad write method arg count: "
+ writeMethod);
}
if (propertyType != null && !params[0].isAssignableFrom(propertyType)) {
throw new IntrospectionException("type mismatch between read and write methods");
}
propertyType = params[0];
}
} catch (IntrospectionException ex) {
throw ex;
}
return propertyType;
}
/**
* Returns a hash code value for the object.
* See {@link java.lang.Object#hashCode} for a complete description.
*
* @return a hash code value for this object.
* @since 1.5
*/
public int hashCode() {
int result = 7;
result = 37 * result + ((getPropertyType() == null) ? 0 :
getPropertyType().hashCode());
result = 37 * result + ((getReadMethod() == null) ? 0 :
getReadMethod().hashCode());
result = 37 * result + ((getWriteMethod() == null) ? 0 :
getWriteMethod().hashCode());
result = 37 * result + ((getPropertyEditorClass() == null) ? 0 :
getPropertyEditorClass().hashCode());
result = 37 * result + ((writeMethodName == null) ? 0 :
writeMethodName.hashCode());
result = 37 * result + ((readMethodName == null) ? 0 :
readMethodName.hashCode());
result = 37 * result + getName().hashCode();
result = 37 * result + ((bound == false) ? 0 : 1);
result = 37 * result + ((constrained == false) ? 0 : 1);
return result;
}
// Calculate once since capitalize() is expensive.
String getBaseName() {
if (baseName == null) {
baseName = NameGenerator.capitalize(getName());
}
return baseName;
}
void appendTo(StringBuilder sb) {
appendTo(sb, "bound", this.bound);
appendTo(sb, "constrained", this.constrained);
appendTo(sb, "propertyEditorClass", this.propertyEditorClassRef);
appendTo(sb, "propertyType", this.propertyTypeRef);
appendTo(sb, "readMethod", this.readMethodRef.get());
appendTo(sb, "writeMethod", this.writeMethodRef.get());
}
boolean isAssignable(Method m1, Method m2) {
if (m1 == null) {
return true; // choose second method
}
if (m2 == null) {
return false; // choose first method
}
if (!m1.getName().equals(m2.getName())) {
return true; // choose second method by default
}
Class<?> type1 = m1.getDeclaringClass();
Class<?> type2 = m2.getDeclaringClass();
if (!type1.isAssignableFrom(type2)) {
return false; // choose first method: it declared later
}
type1 = getReturnType(getClass0(), m1);
type2 = getReturnType(getClass0(), m2);
if (!type1.isAssignableFrom(type2)) {
return false; // choose first method: it overrides return type
}
Class<?>[] args1 = getParameterTypes(getClass0(), m1);
Class<?>[] args2 = getParameterTypes(getClass0(), m2);
if (args1.length != args2.length) {
return true; // choose second method by default
}
for (int i = 0; i < args1.length; i++) {
if (!args1[i].isAssignableFrom(args2[i])) {
return false; // choose first method: it overrides parameter
}
}
return true; // choose second method
}
}

View File

@@ -0,0 +1,225 @@
/*
* Copyright (c) 1996, 2003, 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;
/**
* A PropertyEditor class provides support for GUIs that want to
* allow users to edit a property value of a given type.
* <p>
* PropertyEditor supports a variety of different kinds of ways of
* displaying and updating property values. Most PropertyEditors will
* only need to support a subset of the different options available in
* this API.
* <P>
* Simple PropertyEditors may only support the getAsText and setAsText
* methods and need not support (say) paintValue or getCustomEditor. More
* complex types may be unable to support getAsText and setAsText but will
* instead support paintValue and getCustomEditor.
* <p>
* Every propertyEditor must support one or more of the three simple
* display styles. Thus it can either (1) support isPaintable or (2)
* both return a non-null String[] from getTags() and return a non-null
* value from getAsText or (3) simply return a non-null String from
* getAsText().
* <p>
* Every property editor must support a call on setValue when the argument
* object is of the type for which this is the corresponding propertyEditor.
* In addition, each property editor must either support a custom editor,
* or support setAsText.
* <p>
* Each PropertyEditor should have a null constructor.
*/
public interface PropertyEditor {
/**
* Set (or change) the object that is to be edited. Primitive types such
* as "int" must be wrapped as the corresponding object type such as
* "java.lang.Integer".
*
* @param value The new target object to be edited. Note that this
* object should not be modified by the PropertyEditor, rather
* the PropertyEditor should create a new object to hold any
* modified value.
*/
void setValue(Object value);
/**
* Gets the property value.
*
* @return The value of the property. Primitive types such as "int" will
* be wrapped as the corresponding object type such as "java.lang.Integer".
*/
Object getValue();
//----------------------------------------------------------------------
/**
* Determines whether this property editor is paintable.
*
* @return True if the class will honor the paintValue method.
*/
boolean isPaintable();
/**
* Paint a representation of the value into a given area of screen
* real estate. Note that the propertyEditor is responsible for doing
* its own clipping so that it fits into the given rectangle.
* <p>
* If the PropertyEditor doesn't honor paint requests (see isPaintable)
* this method should be a silent noop.
* <p>
* The given Graphics object will have the default font, color, etc of
* the parent container. The PropertyEditor may change graphics attributes
* such as font and color and doesn't need to restore the old values.
*
* @param gfx Graphics object to paint into.
* @param box Rectangle within graphics object into which we should paint.
*/
void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box);
//----------------------------------------------------------------------
/**
* Returns a fragment of Java code that can be used to set a property
* to match the editors current state. This method is intended
* for use when generating Java code to reflect changes made through the
* property editor.
* <p>
* The code fragment should be context free and must be a legal Java
* expression as specified by the JLS.
* <p>
* Specifically, if the expression represents a computation then all
* classes and static members should be fully qualified. This rule
* applies to constructors, static methods and non primitive arguments.
* <p>
* Caution should be used when evaluating the expression as it may throw
* exceptions. In particular, code generators must ensure that generated
* code will compile in the presence of an expression that can throw
* checked exceptions.
* <p>
* Example results are:
* <ul>
* <li>Primitive expresssion: <code>2</code>
* <li>Class constructor: <code>new java.awt.Color(127,127,34)</code>
* <li>Static field: <code>java.awt.Color.orange</code>
* <li>Static method: <code>javax.swing.Box.createRigidArea(new
* java.awt.Dimension(0, 5))</code>
* </ul>
*
* @return a fragment of Java code representing an initializer for the
* current value. It should not contain a semi-colon
* ('<code>;</code>') to end the expression.
*/
String getJavaInitializationString();
//----------------------------------------------------------------------
/**
* Gets the property value as text.
*
* @return The property value as a human editable string.
* <p> Returns null if the value can't be expressed as an editable string.
* <p> If a non-null value is returned, then the PropertyEditor should
* be prepared to parse that string back in setAsText().
*/
String getAsText();
/**
* Set the property value by parsing a given String. May raise
* java.lang.IllegalArgumentException if either the String is
* badly formatted or if this kind of property can't be expressed
* as text.
* @param text The string to be parsed.
*/
void setAsText(String text) throws java.lang.IllegalArgumentException;
//----------------------------------------------------------------------
/**
* If the property value must be one of a set of known tagged values,
* then this method should return an array of the tags. This can
* be used to represent (for example) enum values. If a PropertyEditor
* supports tags, then it should support the use of setAsText with
* a tag value as a way of setting the value and the use of getAsText
* to identify the current value.
*
* @return The tag values for this property. May be null if this
* property cannot be represented as a tagged value.
*
*/
String[] getTags();
//----------------------------------------------------------------------
/**
* A PropertyEditor may choose to make available a full custom Component
* that edits its property value. It is the responsibility of the
* PropertyEditor to hook itself up to its editor Component itself and
* to report property value changes by firing a PropertyChange event.
* <P>
* The higher-level code that calls getCustomEditor may either embed
* the Component in some larger property sheet, or it may put it in
* its own individual dialog, or ...
*
* @return A java.awt.Component that will allow a human to directly
* edit the current property value. May be null if this is
* not supported.
*/
java.awt.Component getCustomEditor();
/**
* Determines whether this property editor supports a custom editor.
*
* @return True if the propertyEditor can provide a custom editor.
*/
boolean supportsCustomEditor();
//----------------------------------------------------------------------
/**
* Adds a listener for the value change.
* When the property editor changes its value
* it should fire a {@link PropertyChangeEvent}
* on all registered {@link PropertyChangeListener}s,
* specifying the {@code null} value for the property name
* and itself as the source.
*
* @param listener the {@link PropertyChangeListener} to add
*/
void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Removes a listener for the value change.
*
* @param listener the {@link PropertyChangeListener} to remove
*/
void removePropertyChangeListener(PropertyChangeListener listener);
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 1996, 2011, 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;
/**
* The PropertyEditorManager can be used to locate a property editor for
* any given type name. This property editor must support the
* java.beans.PropertyEditor interface for editing a given object.
* <P>
* The PropertyEditorManager uses three techniques for locating an editor
* for a given type. First, it provides a registerEditor method to allow
* an editor to be specifically registered for a given type. Second it
* tries to locate a suitable class by adding "Editor" to the full
* qualified classname of the given type (e.g. "foo.bah.FozEditor").
* Finally it takes the simple classname (without the package name) adds
* "Editor" to it and looks in a search-path of packages for a matching
* class.
* <P>
* So for an input class foo.bah.Fred, the PropertyEditorManager would
* first look in its tables to see if an editor had been registered for
* foo.bah.Fred and if so use that. Then it will look for a
* foo.bah.FredEditor class. Then it will look for (say)
* standardEditorsPackage.FredEditor class.
* <p>
* Default PropertyEditors will be provided for the Java primitive types
* "boolean", "byte", "short", "int", "long", "float", and "double"; and
* for the classes java.lang.String. java.awt.Color, and java.awt.Font.
*/
public class PropertyEditorManager {
/**
* Registers an editor class to edit values of the given target class.
* If the editor class is {@code null},
* then any existing definition will be removed.
* Thus this method can be used to cancel the registration.
* The registration is canceled automatically
* if either the target or editor class is unloaded.
* <p>
* If there is a security manager, its {@code checkPropertiesAccess}
* method is called. This could result in a {@linkplain SecurityException}.
*
* @param targetType the class object of the type to be edited
* @param editorClass the class object of the editor class
* @throws SecurityException if a security manager exists and
* its {@code checkPropertiesAccess} method
* doesn't allow setting of system properties
*
* @see SecurityManager#checkPropertiesAccess
*/
public static void registerEditor(Class<?> targetType, Class<?> editorClass) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
ThreadGroupContext.getContext().getPropertyEditorFinder().register(targetType, editorClass);
}
/**
* Locate a value editor for a given target type.
*
* @param targetType The Class object for the type to be edited
* @return An editor object for the given target class.
* The result is null if no suitable editor can be found.
*/
public static PropertyEditor findEditor(Class<?> targetType) {
return ThreadGroupContext.getContext().getPropertyEditorFinder().find(targetType);
}
/**
* Gets the package names that will be searched for property editors.
*
* @return The array of package names that will be searched in
* order to find property editors.
* <p> The default value for this array is implementation-dependent,
* e.g. Sun implementation initially sets to {"sun.beans.editors"}.
*/
public static String[] getEditorSearchPath() {
return ThreadGroupContext.getContext().getPropertyEditorFinder().getPackages();
}
/**
* Change the list of package names that will be used for
* finding property editors.
*
* <p>First, if there is a security manager, its <code>checkPropertiesAccess</code>
* method is called. This could result in a SecurityException.
*
* @param path Array of package names.
* @exception SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow setting
* of system properties.
* @see SecurityManager#checkPropertiesAccess
*/
public static void setEditorSearchPath(String[] path) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
ThreadGroupContext.getContext().getPropertyEditorFinder().setPackages(path);
}
}

View File

@@ -0,0 +1,307 @@
/*
* Copyright (c) 1996, 2013, 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 java.beans.*;
/**
* This is a support class to help build property editors.
* <p>
* It can be used either as a base class or as a delegate.
*/
public class PropertyEditorSupport implements PropertyEditor {
/**
* Constructs a <code>PropertyEditorSupport</code> object.
*
* @since 1.5
*/
public PropertyEditorSupport() {
setSource(this);
}
/**
* Constructs a <code>PropertyEditorSupport</code> object.
*
* @param source the source used for event firing
* @since 1.5
*/
public PropertyEditorSupport(Object source) {
if (source == null) {
throw new NullPointerException();
}
setSource(source);
}
/**
* Returns the bean that is used as the
* source of events. If the source has not
* been explicitly set then this instance of
* <code>PropertyEditorSupport</code> is returned.
*
* @return the source object or this instance
* @since 1.5
*/
public Object getSource() {
return source;
}
/**
* Sets the source bean.
* <p>
* The source bean is used as the source of events
* for the property changes. This source should be used for information
* purposes only and should not be modified by the PropertyEditor.
*
* @param source source object to be used for events
* @since 1.5
*/
public void setSource(Object source) {
this.source = source;
}
/**
* Set (or change) the object that is to be edited.
*
* @param value The new target object to be edited. Note that this
* object should not be modified by the PropertyEditor, rather
* the PropertyEditor should create a new object to hold any
* modified value.
*/
public void setValue(Object value) {
this.value = value;
firePropertyChange();
}
/**
* Gets the value of the property.
*
* @return The value of the property.
*/
public Object getValue() {
return value;
}
//----------------------------------------------------------------------
/**
* Determines whether the class will honor the paintValue method.
*
* @return True if the class will honor the paintValue method.
*/
public boolean isPaintable() {
return false;
}
/**
* Paint a representation of the value into a given area of screen
* real estate. Note that the propertyEditor is responsible for doing
* its own clipping so that it fits into the given rectangle.
* <p>
* If the PropertyEditor doesn't honor paint requests (see isPaintable)
* this method should be a silent noop.
*
* @param gfx Graphics object to paint into.
* @param box Rectangle within graphics object into which we should paint.
*/
public void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box) {
}
//----------------------------------------------------------------------
/**
* This method is intended for use when generating Java code to set
* the value of the property. It should return a fragment of Java code
* that can be used to initialize a variable with the current property
* value.
* <p>
* Example results are "2", "new Color(127,127,34)", "Color.orange", etc.
*
* @return A fragment of Java code representing an initializer for the
* current value.
*/
public String getJavaInitializationString() {
return "???";
}
//----------------------------------------------------------------------
/**
* Gets the property value as a string suitable for presentation
* to a human to edit.
*
* @return The property value as a string suitable for presentation
* to a human to edit.
* <p> Returns null if the value can't be expressed as a string.
* <p> If a non-null value is returned, then the PropertyEditor should
* be prepared to parse that string back in setAsText().
*/
public String getAsText() {
return (this.value != null)
? this.value.toString()
: null;
}
/**
* Sets the property value by parsing a given String. May raise
* java.lang.IllegalArgumentException if either the String is
* badly formatted or if this kind of property can't be expressed
* as text.
*
* @param text The string to be parsed.
*/
public void setAsText(String text) throws java.lang.IllegalArgumentException {
if (value instanceof String) {
setValue(text);
return;
}
throw new java.lang.IllegalArgumentException(text);
}
//----------------------------------------------------------------------
/**
* If the property value must be one of a set of known tagged values,
* then this method should return an array of the tag values. This can
* be used to represent (for example) enum values. If a PropertyEditor
* supports tags, then it should support the use of setAsText with
* a tag value as a way of setting the value.
*
* @return The tag values for this property. May be null if this
* property cannot be represented as a tagged value.
*
*/
public String[] getTags() {
return null;
}
//----------------------------------------------------------------------
/**
* A PropertyEditor may chose to make available a full custom Component
* that edits its property value. It is the responsibility of the
* PropertyEditor to hook itself up to its editor Component itself and
* to report property value changes by firing a PropertyChange event.
* <P>
* The higher-level code that calls getCustomEditor may either embed
* the Component in some larger property sheet, or it may put it in
* its own individual dialog, or ...
*
* @return A java.awt.Component that will allow a human to directly
* edit the current property value. May be null if this is
* not supported.
*/
public java.awt.Component getCustomEditor() {
return null;
}
/**
* Determines whether the propertyEditor can provide a custom editor.
*
* @return True if the propertyEditor can provide a custom editor.
*/
public boolean supportsCustomEditor() {
return false;
}
//----------------------------------------------------------------------
/**
* Adds a listener for the value change.
* When the property editor changes its value
* it should fire a {@link PropertyChangeEvent}
* on all registered {@link PropertyChangeListener}s,
* specifying the {@code null} value for the property name.
* If the source property is set,
* it should be used as the source of the event.
* <p>
* The same listener object may be added more than once,
* and will be called as many times as it is added.
* If {@code listener} is {@code null},
* no exception is thrown and no action is taken.
*
* @param listener the {@link PropertyChangeListener} to add
*/
public synchronized void addPropertyChangeListener(
PropertyChangeListener listener) {
if (listeners == null) {
listeners = new java.util.Vector<>();
}
listeners.addElement(listener);
}
/**
* Removes a listener for the value change.
* <p>
* If the same listener was added more than once,
* it will be notified one less time after being removed.
* If {@code listener} is {@code null}, or was never added,
* no exception is thrown and no action is taken.
*
* @param listener the {@link PropertyChangeListener} to remove
*/
public synchronized void removePropertyChangeListener(
PropertyChangeListener listener) {
if (listeners == null) {
return;
}
listeners.removeElement(listener);
}
/**
* Report that we have been modified to any interested listeners.
*/
public void firePropertyChange() {
java.util.Vector<PropertyChangeListener> targets;
synchronized (this) {
if (listeners == null) {
return;
}
targets = unsafeClone(listeners);
}
// Tell our listeners that "everything" has changed.
PropertyChangeEvent evt = new PropertyChangeEvent(source, null, null, null);
for (int i = 0; i < targets.size(); i++) {
PropertyChangeListener target = targets.elementAt(i);
target.propertyChange(evt);
}
}
@SuppressWarnings("unchecked")
private <T> java.util.Vector<T> unsafeClone(java.util.Vector<T> v) {
return (java.util.Vector<T>)v.clone();
}
//----------------------------------------------------------------------
private Object value;
private Object source;
private java.util.Vector<PropertyChangeListener> listeners;
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 1996, 2009, 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;
/**
* A PropertyVetoException is thrown when a proposed change to a
* property represents an unacceptable value.
*/
public
class PropertyVetoException extends Exception {
private static final long serialVersionUID = 129596057694162164L;
/**
* Constructs a <code>PropertyVetoException</code> with a
* detailed message.
*
* @param mess Descriptive message
* @param evt A PropertyChangeEvent describing the vetoed change.
*/
public PropertyVetoException(String mess, PropertyChangeEvent evt) {
super(mess);
this.evt = evt;
}
/**
* Gets the vetoed <code>PropertyChangeEvent</code>.
*
* @return A PropertyChangeEvent describing the vetoed change.
*/
public PropertyChangeEvent getPropertyChangeEvent() {
return evt;
}
/**
* A PropertyChangeEvent describing the vetoed change.
* @serial
*/
private PropertyChangeEvent evt;
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 1996, 2015, 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 java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageProducer;
import java.net.URL;
/**
* This is a support class to make it easier for people to provide
* BeanInfo classes.
* <p>
* It defaults to providing "noop" information, and can be selectively
* overriden to provide more explicit information on chosen topics.
* When the introspector sees the "noop" values, it will apply low
* level introspection and design patterns to automatically analyze
* the target bean.
*/
public class SimpleBeanInfo implements BeanInfo {
/**
* Deny knowledge about the class and customizer of the bean.
* You can override this if you wish to provide explicit info.
*/
public BeanDescriptor getBeanDescriptor() {
return null;
}
/**
* Deny knowledge of properties. You can override this
* if you wish to provide explicit property info.
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return null;
}
/**
* Deny knowledge of a default property. You can override this
* if you wish to define a default property for the bean.
*/
public int getDefaultPropertyIndex() {
return -1;
}
/**
* Deny knowledge of event sets. You can override this
* if you wish to provide explicit event set info.
*/
public EventSetDescriptor[] getEventSetDescriptors() {
return null;
}
/**
* Deny knowledge of a default event. You can override this
* if you wish to define a default event for the bean.
*/
public int getDefaultEventIndex() {
return -1;
}
/**
* Deny knowledge of methods. You can override this
* if you wish to provide explicit method info.
*/
public MethodDescriptor[] getMethodDescriptors() {
return null;
}
/**
* Claim there are no other relevant BeanInfo objects. You
* may override this if you want to (for example) return a
* BeanInfo for a base class.
*/
public BeanInfo[] getAdditionalBeanInfo() {
return null;
}
/**
* Claim there are no icons available. You can override
* this if you want to provide icons for your bean.
*/
public Image getIcon(int iconKind) {
return null;
}
/**
* This is a utility method to help in loading icon images.
* It takes the name of a resource file associated with the
* current object's class file and loads an image object
* from that file. Typically images will be GIFs.
* <p>
* @param resourceName A pathname relative to the directory
* holding the class file of the current class. For example,
* "wombat.gif".
* @return an image object. May be null if the load failed.
*/
public Image loadImage(final String resourceName) {
try {
final URL url = getClass().getResource(resourceName);
if (url != null) {
final ImageProducer ip = (ImageProducer) url.getContent();
if (ip != null) {
return Toolkit.getDefaultToolkit().createImage(ip);
}
}
} catch (final Exception ignored) {
}
return null;
}
}

View File

@@ -0,0 +1,363 @@
/*
* Copyright (c) 2000, 2012, 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 java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import com.sun.beans.finder.ClassFinder;
import com.sun.beans.finder.ConstructorFinder;
import com.sun.beans.finder.MethodFinder;
import sun.reflect.misc.MethodUtil;
/**
* A <code>Statement</code> object represents a primitive statement
* in which a single method is applied to a target and
* a set of arguments - as in <code>"a.setFoo(b)"</code>.
* Note that where this example uses names
* to denote the target and its argument, a statement
* object does not require a name space and is constructed with
* the values themselves.
* The statement object associates the named method
* with its environment as a simple set of values:
* the target and an array of argument values.
*
* @since 1.4
*
* @author Philip Milne
*/
public class Statement {
private static Object[] emptyArray = new Object[]{};
static ExceptionListener defaultExceptionListener = new ExceptionListener() {
public void exceptionThrown(Exception e) {
System.err.println(e);
// e.printStackTrace();
System.err.println("Continuing ...");
}
};
private final AccessControlContext acc = AccessController.getContext();
private final Object target;
private final String methodName;
private final Object[] arguments;
ClassLoader loader;
/**
* Creates a new {@link Statement} object
* for the specified target object to invoke the method
* specified by the name and by the array of arguments.
* <p>
* The {@code target} and the {@code methodName} values should not be {@code null}.
* Otherwise an attempt to execute this {@code Expression}
* will result in a {@code NullPointerException}.
* If the {@code arguments} value is {@code null},
* an empty array is used as the value of the {@code arguments} property.
*
* @param target the target object of this statement
* @param methodName the name of the method to invoke on the specified target
* @param arguments the array of arguments to invoke the specified method
*/
@ConstructorProperties({"target", "methodName", "arguments"})
public Statement(Object target, String methodName, Object[] arguments) {
this.target = target;
this.methodName = methodName;
this.arguments = (arguments == null) ? emptyArray : arguments.clone();
}
/**
* Returns the target object of this statement.
* If this method returns {@code null},
* the {@link #execute} method
* throws a {@code NullPointerException}.
*
* @return the target object of this statement
*/
public Object getTarget() {
return target;
}
/**
* Returns the name of the method to invoke.
* If this method returns {@code null},
* the {@link #execute} method
* throws a {@code NullPointerException}.
*
* @return the name of the method
*/
public String getMethodName() {
return methodName;
}
/**
* Returns the arguments for the method to invoke.
* The number of arguments and their types
* must match the method being called.
* {@code null} can be used as a synonym of an empty array.
*
* @return the array of arguments
*/
public Object[] getArguments() {
return this.arguments.clone();
}
/**
* The {@code execute} method finds a method whose name is the same
* as the {@code methodName} property, and invokes the method on
* the target.
*
* When the target's class defines many methods with the given name
* the implementation should choose the most specific method using
* the algorithm specified in the Java Language Specification
* (15.11). The dynamic class of the target and arguments are used
* in place of the compile-time type information and, like the
* {@link java.lang.reflect.Method} class itself, conversion between
* primitive values and their associated wrapper classes is handled
* internally.
* <p>
* The following method types are handled as special cases:
* <ul>
* <li>
* Static methods may be called by using a class object as the target.
* <li>
* The reserved method name "new" may be used to call a class's constructor
* as if all classes defined static "new" methods. Constructor invocations
* are typically considered {@code Expression}s rather than {@code Statement}s
* as they return a value.
* <li>
* The method names "get" and "set" defined in the {@link java.util.List}
* interface may also be applied to array instances, mapping to
* the static methods of the same name in the {@code Array} class.
* </ul>
*
* @throws NullPointerException if the value of the {@code target} or
* {@code methodName} property is {@code null}
* @throws NoSuchMethodException if a matching method is not found
* @throws SecurityException if a security manager exists and
* it denies the method invocation
* @throws Exception that is thrown by the invoked method
*
* @see java.lang.reflect.Method
*/
public void execute() throws Exception {
invoke();
}
Object invoke() throws Exception {
AccessControlContext acc = this.acc;
if ((acc == null) && (System.getSecurityManager() != null)) {
throw new SecurityException("AccessControlContext is not set");
}
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return invokeInternal();
}
},
acc
);
}
catch (PrivilegedActionException exception) {
throw exception.getException();
}
}
private Object invokeInternal() throws Exception {
Object target = getTarget();
String methodName = getMethodName();
if (target == null || methodName == null) {
throw new NullPointerException((target == null ? "target" :
"methodName") + " should not be null");
}
Object[] arguments = getArguments();
if (arguments == null) {
arguments = emptyArray;
}
// Class.forName() won't load classes outside
// of core from a class inside core. Special
// case this method.
if (target == Class.class && methodName.equals("forName")) {
return ClassFinder.resolveClass((String)arguments[0], this.loader);
}
Class<?>[] argClasses = new Class<?>[arguments.length];
for(int i = 0; i < arguments.length; i++) {
argClasses[i] = (arguments[i] == null) ? null : arguments[i].getClass();
}
AccessibleObject m = null;
if (target instanceof Class) {
/*
For class methods, simluate the effect of a meta class
by taking the union of the static methods of the
actual class, with the instance methods of "Class.class"
and the overloaded "newInstance" methods defined by the
constructors.
This way "System.class", for example, will perform both
the static method getProperties() and the instance method
getSuperclass() defined in "Class.class".
*/
if (methodName.equals("new")) {
methodName = "newInstance";
}
// Provide a short form for array instantiation by faking an nary-constructor.
if (methodName.equals("newInstance") && ((Class)target).isArray()) {
Object result = Array.newInstance(((Class)target).getComponentType(), arguments.length);
for(int i = 0; i < arguments.length; i++) {
Array.set(result, i, arguments[i]);
}
return result;
}
if (methodName.equals("newInstance") && arguments.length != 0) {
// The Character class, as of 1.4, does not have a constructor
// which takes a String. All of the other "wrapper" classes
// for Java's primitive types have a String constructor so we
// fake such a constructor here so that this special case can be
// ignored elsewhere.
if (target == Character.class && arguments.length == 1 &&
argClasses[0] == String.class) {
return new Character(((String)arguments[0]).charAt(0));
}
try {
m = ConstructorFinder.findConstructor((Class)target, argClasses);
}
catch (NoSuchMethodException exception) {
m = null;
}
}
if (m == null && target != Class.class) {
m = getMethod((Class)target, methodName, argClasses);
}
if (m == null) {
m = getMethod(Class.class, methodName, argClasses);
}
}
else {
/*
This special casing of arrays is not necessary, but makes files
involving arrays much shorter and simplifies the archiving infrastrcure.
The Array.set() method introduces an unusual idea - that of a static method
changing the state of an instance. Normally statements with side
effects on objects are instance methods of the objects themselves
and we reinstate this rule (perhaps temporarily) by special-casing arrays.
*/
if (target.getClass().isArray() &&
(methodName.equals("set") || methodName.equals("get"))) {
int index = ((Integer)arguments[0]).intValue();
if (methodName.equals("get")) {
return Array.get(target, index);
}
else {
Array.set(target, index, arguments[1]);
return null;
}
}
m = getMethod(target.getClass(), methodName, argClasses);
}
if (m != null) {
try {
if (m instanceof Method) {
return MethodUtil.invoke((Method)m, target, arguments);
}
else {
return ((Constructor)m).newInstance(arguments);
}
}
catch (IllegalAccessException iae) {
throw new Exception("Statement cannot invoke: " +
methodName + " on " + target.getClass(),
iae);
}
catch (InvocationTargetException ite) {
Throwable te = ite.getTargetException();
if (te instanceof Exception) {
throw (Exception)te;
}
else {
throw ite;
}
}
}
throw new NoSuchMethodException(toString());
}
String instanceName(Object instance) {
if (instance == null) {
return "null";
} else if (instance.getClass() == String.class) {
return "\""+(String)instance + "\"";
} else {
// Note: there is a minor problem with using the non-caching
// NameGenerator method. The return value will not have
// specific information about the inner class name. For example,
// In 1.4.2 an inner class would be represented as JList$1 now
// would be named Class.
return NameGenerator.unqualifiedClassName(instance.getClass());
}
}
/**
* Prints the value of this statement using a Java-style syntax.
*/
public String toString() {
// Respect a subclass's implementation here.
Object target = getTarget();
String methodName = getMethodName();
Object[] arguments = getArguments();
if (arguments == null) {
arguments = emptyArray;
}
StringBuffer result = new StringBuffer(instanceName(target) + "." + methodName + "(");
int n = arguments.length;
for(int i = 0; i < n; i++) {
result.append(instanceName(arguments[i]));
if (i != n -1) {
result.append(", ");
}
}
result.append(");");
return result.toString();
}
static Method getMethod(Class<?> type, String name, Class<?>... args) {
try {
return MethodFinder.findMethod(type, name, args);
}
catch (NoSuchMethodException exception) {
return null;
}
}
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2011, 2013, 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.finder.BeanInfoFinder;
import com.sun.beans.finder.PropertyEditorFinder;
import java.awt.GraphicsEnvironment;
import java.util.Map;
import java.util.WeakHashMap;
/**
* The {@code ThreadGroupContext} is an application-dependent
* context referenced by the specific {@link ThreadGroup}.
* This is a replacement for the {@link sun.awt.AppContext}.
*
* @author Sergey Malenkov
*/
final class ThreadGroupContext {
private static final WeakIdentityMap<ThreadGroupContext> contexts = new WeakIdentityMap<ThreadGroupContext>() {
protected ThreadGroupContext create(Object key) {
return new ThreadGroupContext();
}
};
/**
* Returns the appropriate {@code ThreadGroupContext} for the caller,
* as determined by its {@code ThreadGroup}.
*
* @return the application-dependent context
*/
static ThreadGroupContext getContext() {
return contexts.get(Thread.currentThread().getThreadGroup());
}
private volatile boolean isDesignTime;
private volatile Boolean isGuiAvailable;
private Map<Class<?>, BeanInfo> beanInfoCache;
private BeanInfoFinder beanInfoFinder;
private PropertyEditorFinder propertyEditorFinder;
private ThreadGroupContext() {
}
boolean isDesignTime() {
return this.isDesignTime;
}
void setDesignTime(boolean isDesignTime) {
this.isDesignTime = isDesignTime;
}
boolean isGuiAvailable() {
Boolean isGuiAvailable = this.isGuiAvailable;
return (isGuiAvailable != null)
? isGuiAvailable.booleanValue()
: !GraphicsEnvironment.isHeadless();
}
void setGuiAvailable(boolean isGuiAvailable) {
this.isGuiAvailable = Boolean.valueOf(isGuiAvailable);
}
BeanInfo getBeanInfo(Class<?> type) {
return (this.beanInfoCache != null)
? this.beanInfoCache.get(type)
: null;
}
BeanInfo putBeanInfo(Class<?> type, BeanInfo info) {
if (this.beanInfoCache == null) {
this.beanInfoCache = new WeakHashMap<>();
}
return this.beanInfoCache.put(type, info);
}
void removeBeanInfo(Class<?> type) {
if (this.beanInfoCache != null) {
this.beanInfoCache.remove(type);
}
}
void clearBeanInfoCache() {
if (this.beanInfoCache != null) {
this.beanInfoCache.clear();
}
}
synchronized BeanInfoFinder getBeanInfoFinder() {
if (this.beanInfoFinder == null) {
this.beanInfoFinder = new BeanInfoFinder();
}
return this.beanInfoFinder;
}
synchronized PropertyEditorFinder getPropertyEditorFinder() {
if (this.propertyEditorFinder == null) {
this.propertyEditorFinder = new PropertyEditorFinder();
}
return this.propertyEditorFinder;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2008, 2013, 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 java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Indicates that an attribute called "transient"
* should be declared with the given {@code value}
* when the {@link Introspector} constructs
* a {@link PropertyDescriptor} or {@link EventSetDescriptor}
* classes associated with the annotated code element.
* A {@code true} value for the "transient" attribute
* indicates to encoders derived from {@link Encoder}
* that this feature should be ignored.
* <p>
* The {@code Transient} annotation may be be used
* in any of the methods that are involved
* in a {@link FeatureDescriptor} subclass
* to identify the transient feature in the annotated class and its subclasses.
* Normally, the method that starts with "get" is the best place
* to put the annotation and it is this declaration
* that takes precedence in the case of multiple annotations
* being defined for the same feature.
* <p>
* To declare a feature non-transient in a class
* whose superclass declares it transient,
* use {@code @Transient(false)}.
* In all cases, the {@link Introspector} decides
* if a feature is transient by referring to the annotation
* on the most specific superclass.
* If no {@code Transient} annotation is present
* in any superclass the feature is not transient.
*
* @since 1.7
*/
@Target({METHOD})
@Retention(RUNTIME)
public @interface Transient {
/**
* Returns whether or not the {@code Introspector} should
* construct artifacts for the annotated method.
* @return whether or not the {@code Introspector} should
* construct artifacts for the annotated method
*/
boolean value() default true;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 1996, 1997, 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;
/**
* A VetoableChange event gets fired whenever a bean changes a "constrained"
* property. You can register a VetoableChangeListener with a source bean
* so as to be notified of any constrained property updates.
*/
public interface VetoableChangeListener extends java.util.EventListener {
/**
* This method gets called when a constrained property is changed.
*
* @param evt a <code>PropertyChangeEvent</code> object describing the
* event source and the property that has changed.
* @exception PropertyVetoException if the recipient wishes the property
* change to be rolled back.
*/
void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException;
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2000, 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 java.util.EventListenerProxy;
/**
* A class which extends the {@code EventListenerProxy}
* specifically for adding a {@code VetoableChangeListener}
* with a "constrained" property.
* Instances of this class can be added
* as {@code VetoableChangeListener}s to a bean
* which supports firing vetoable change events.
* <p>
* If the object has a {@code getVetoableChangeListeners} method
* then the array returned could be a mixture of {@code VetoableChangeListener}
* and {@code VetoableChangeListenerProxy} objects.
*
* @see java.util.EventListenerProxy
* @see VetoableChangeSupport#getVetoableChangeListeners
* @since 1.4
*/
public class VetoableChangeListenerProxy
extends EventListenerProxy<VetoableChangeListener>
implements VetoableChangeListener {
private final String propertyName;
/**
* Constructor which binds the {@code VetoableChangeListener}
* to a specific property.
*
* @param propertyName the name of the property to listen on
* @param listener the listener object
*/
public VetoableChangeListenerProxy(String propertyName, VetoableChangeListener listener) {
super(listener);
this.propertyName = propertyName;
}
/**
* Forwards the property change event to the listener delegate.
*
* @param event the property change event
*
* @exception PropertyVetoException if the recipient wishes the property
* change to be rolled back
*/
public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException{
getListener().vetoableChange(event);
}
/**
* Returns the name of the named property associated with the listener.
*
* @return the name of the named property associated with the listener
*/
public String getPropertyName() {
return this.propertyName;
}
}

View File

@@ -0,0 +1,536 @@
/*
* Copyright (c) 1996, 2013, 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 java.io.Serializable;
import java.io.ObjectStreamField;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map.Entry;
/**
* This is a utility class that can be used by beans that support constrained
* properties. It manages a list of listeners and dispatches
* {@link PropertyChangeEvent}s to them. You can use an instance of this class
* as a member field of your bean and delegate these types of work to it.
* The {@link VetoableChangeListener} can be registered for all properties
* or for a property specified by name.
* <p>
* Here is an example of {@code VetoableChangeSupport} usage that follows
* the rules and recommendations laid out in the JavaBeans&trade; specification:
* <pre>{@code
* public class MyBean {
* private final VetoableChangeSupport vcs = new VetoableChangeSupport(this);
*
* public void addVetoableChangeListener(VetoableChangeListener listener) {
* this.vcs.addVetoableChangeListener(listener);
* }
*
* public void removeVetoableChangeListener(VetoableChangeListener listener) {
* this.vcs.removeVetoableChangeListener(listener);
* }
*
* private String value;
*
* public String getValue() {
* return this.value;
* }
*
* public void setValue(String newValue) throws PropertyVetoException {
* String oldValue = this.value;
* this.vcs.fireVetoableChange("value", oldValue, newValue);
* this.value = newValue;
* }
*
* [...]
* }
* }</pre>
* <p>
* A {@code VetoableChangeSupport} instance is thread-safe.
* <p>
* This class is serializable. When it is serialized it will save
* (and restore) any listeners that are themselves serializable. Any
* non-serializable listeners will be skipped during serialization.
*
* @see PropertyChangeSupport
*/
public class VetoableChangeSupport implements Serializable {
private VetoableChangeListenerMap map = new VetoableChangeListenerMap();
/**
* Constructs a <code>VetoableChangeSupport</code> object.
*
* @param sourceBean The bean to be given as the source for any events.
*/
public VetoableChangeSupport(Object sourceBean) {
if (sourceBean == null) {
throw new NullPointerException();
}
source = sourceBean;
}
/**
* Add a VetoableChangeListener to the listener list.
* The listener is registered for all properties.
* The same listener object may be added more than once, and will be called
* as many times as it is added.
* If <code>listener</code> is null, no exception is thrown and no action
* is taken.
*
* @param listener The VetoableChangeListener to be added
*/
public void addVetoableChangeListener(VetoableChangeListener listener) {
if (listener == null) {
return;
}
if (listener instanceof VetoableChangeListenerProxy) {
VetoableChangeListenerProxy proxy =
(VetoableChangeListenerProxy)listener;
// Call two argument add method.
addVetoableChangeListener(proxy.getPropertyName(),
proxy.getListener());
} else {
this.map.add(null, listener);
}
}
/**
* Remove a VetoableChangeListener from the listener list.
* This removes a VetoableChangeListener that was registered
* for all properties.
* If <code>listener</code> was added more than once to the same event
* source, it will be notified one less time after being removed.
* If <code>listener</code> is null, or was never added, no exception is
* thrown and no action is taken.
*
* @param listener The VetoableChangeListener to be removed
*/
public void removeVetoableChangeListener(VetoableChangeListener listener) {
if (listener == null) {
return;
}
if (listener instanceof VetoableChangeListenerProxy) {
VetoableChangeListenerProxy proxy =
(VetoableChangeListenerProxy)listener;
// Call two argument remove method.
removeVetoableChangeListener(proxy.getPropertyName(),
proxy.getListener());
} else {
this.map.remove(null, listener);
}
}
/**
* Returns an array of all the listeners that were added to the
* VetoableChangeSupport object with addVetoableChangeListener().
* <p>
* If some listeners have been added with a named property, then
* the returned array will be a mixture of VetoableChangeListeners
* and <code>VetoableChangeListenerProxy</code>s. If the calling
* method is interested in distinguishing the listeners then it must
* test each element to see if it's a
* <code>VetoableChangeListenerProxy</code>, perform the cast, and examine
* the parameter.
*
* <pre>{@code
* VetoableChangeListener[] listeners = bean.getVetoableChangeListeners();
* for (int i = 0; i < listeners.length; i++) {
* if (listeners[i] instanceof VetoableChangeListenerProxy) {
* VetoableChangeListenerProxy proxy =
* (VetoableChangeListenerProxy)listeners[i];
* if (proxy.getPropertyName().equals("foo")) {
* // proxy is a VetoableChangeListener which was associated
* // with the property named "foo"
* }
* }
* }
* }</pre>
*
* @see VetoableChangeListenerProxy
* @return all of the <code>VetoableChangeListeners</code> added or an
* empty array if no listeners have been added
* @since 1.4
*/
public VetoableChangeListener[] getVetoableChangeListeners(){
return this.map.getListeners();
}
/**
* Add a VetoableChangeListener for a specific property. The listener
* will be invoked only when a call on fireVetoableChange names that
* specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>propertyName</code> or <code>listener</code> is null, no
* exception is thrown and no action is taken.
*
* @param propertyName The name of the property to listen on.
* @param listener The VetoableChangeListener to be added
*/
public void addVetoableChangeListener(
String propertyName,
VetoableChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
listener = this.map.extract(listener);
if (listener != null) {
this.map.add(propertyName, listener);
}
}
/**
* Remove a VetoableChangeListener for a specific property.
* If <code>listener</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>propertyName</code> is null, no exception is thrown and no
* action is taken.
* If <code>listener</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param propertyName The name of the property that was listened on.
* @param listener The VetoableChangeListener to be removed
*/
public void removeVetoableChangeListener(
String propertyName,
VetoableChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
listener = this.map.extract(listener);
if (listener != null) {
this.map.remove(propertyName, listener);
}
}
/**
* Returns an array of all the listeners which have been associated
* with the named property.
*
* @param propertyName The name of the property being listened to
* @return all the <code>VetoableChangeListeners</code> associated with
* the named property. If no such listeners have been added,
* or if <code>propertyName</code> is null, an empty array is
* returned.
* @since 1.4
*/
public VetoableChangeListener[] getVetoableChangeListeners(String propertyName) {
return this.map.getListeners(propertyName);
}
/**
* Reports a constrained property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* Any listener can throw a {@code PropertyVetoException} to veto the update.
* If one of the listeners vetoes the update, this method passes
* a new "undo" {@code PropertyChangeEvent} that reverts to the old value
* to all listeners that already confirmed this update
* and throws the {@code PropertyVetoException} again.
* <p>
* No event is fired if old and new values are equal and non-null.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #fireVetoableChange(PropertyChangeEvent)} method.
*
* @param propertyName the programmatic name of the property that is about to change
* @param oldValue the old value of the property
* @param newValue the new value of the property
* @throws PropertyVetoException if one of listeners vetoes the property update
*/
public void fireVetoableChange(String propertyName, Object oldValue, Object newValue)
throws PropertyVetoException {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
fireVetoableChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
}
}
/**
* Reports an integer constrained property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* Any listener can throw a {@code PropertyVetoException} to veto the update.
* If one of the listeners vetoes the update, this method passes
* a new "undo" {@code PropertyChangeEvent} that reverts to the old value
* to all listeners that already confirmed this update
* and throws the {@code PropertyVetoException} again.
* <p>
* No event is fired if old and new values are equal.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #fireVetoableChange(String, Object, Object)} method.
*
* @param propertyName the programmatic name of the property that is about to change
* @param oldValue the old value of the property
* @param newValue the new value of the property
* @throws PropertyVetoException if one of listeners vetoes the property update
*/
public void fireVetoableChange(String propertyName, int oldValue, int newValue)
throws PropertyVetoException {
if (oldValue != newValue) {
fireVetoableChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
}
}
/**
* Reports a boolean constrained property update to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* Any listener can throw a {@code PropertyVetoException} to veto the update.
* If one of the listeners vetoes the update, this method passes
* a new "undo" {@code PropertyChangeEvent} that reverts to the old value
* to all listeners that already confirmed this update
* and throws the {@code PropertyVetoException} again.
* <p>
* No event is fired if old and new values are equal.
* <p>
* This is merely a convenience wrapper around the more general
* {@link #fireVetoableChange(String, Object, Object)} method.
*
* @param propertyName the programmatic name of the property that is about to change
* @param oldValue the old value of the property
* @param newValue the new value of the property
* @throws PropertyVetoException if one of listeners vetoes the property update
*/
public void fireVetoableChange(String propertyName, boolean oldValue, boolean newValue)
throws PropertyVetoException {
if (oldValue != newValue) {
fireVetoableChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
}
}
/**
* Fires a property change event to listeners
* that have been registered to track updates of
* all properties or a property with the specified name.
* <p>
* Any listener can throw a {@code PropertyVetoException} to veto the update.
* If one of the listeners vetoes the update, this method passes
* a new "undo" {@code PropertyChangeEvent} that reverts to the old value
* to all listeners that already confirmed this update
* and throws the {@code PropertyVetoException} again.
* <p>
* No event is fired if the given event's old and new values are equal and non-null.
*
* @param event the {@code PropertyChangeEvent} to be fired
* @throws PropertyVetoException if one of listeners vetoes the property update
*/
public void fireVetoableChange(PropertyChangeEvent event)
throws PropertyVetoException {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
String name = event.getPropertyName();
VetoableChangeListener[] common = this.map.get(null);
VetoableChangeListener[] named = (name != null)
? this.map.get(name)
: null;
VetoableChangeListener[] listeners;
if (common == null) {
listeners = named;
}
else if (named == null) {
listeners = common;
}
else {
listeners = new VetoableChangeListener[common.length + named.length];
System.arraycopy(common, 0, listeners, 0, common.length);
System.arraycopy(named, 0, listeners, common.length, named.length);
}
if (listeners != null) {
int current = 0;
try {
while (current < listeners.length) {
listeners[current].vetoableChange(event);
current++;
}
}
catch (PropertyVetoException veto) {
event = new PropertyChangeEvent(this.source, name, newValue, oldValue);
for (int i = 0; i < current; i++) {
try {
listeners[i].vetoableChange(event);
}
catch (PropertyVetoException exception) {
// ignore exceptions that occur during rolling back
}
}
throw veto; // rethrow the veto exception
}
}
}
}
/**
* Check if there are any listeners for a specific property, including
* those registered on all properties. If <code>propertyName</code>
* is null, only check for listeners registered on all properties.
*
* @param propertyName the property name.
* @return true if there are one or more listeners for the given property
*/
public boolean hasListeners(String propertyName) {
return this.map.hasListeners(propertyName);
}
/**
* @serialData Null terminated list of <code>VetoableChangeListeners</code>.
* <p>
* At serialization time we skip non-serializable listeners and
* only serialize the serializable listeners.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
Hashtable<String, VetoableChangeSupport> children = null;
VetoableChangeListener[] listeners = null;
synchronized (this.map) {
for (Entry<String, VetoableChangeListener[]> entry : this.map.getEntries()) {
String property = entry.getKey();
if (property == null) {
listeners = entry.getValue();
} else {
if (children == null) {
children = new Hashtable<>();
}
VetoableChangeSupport vcs = new VetoableChangeSupport(this.source);
vcs.map.set(null, entry.getValue());
children.put(property, vcs);
}
}
}
ObjectOutputStream.PutField fields = s.putFields();
fields.put("children", children);
fields.put("source", this.source);
fields.put("vetoableChangeSupportSerializedDataVersion", 2);
s.writeFields();
if (listeners != null) {
for (VetoableChangeListener l : listeners) {
if (l instanceof Serializable) {
s.writeObject(l);
}
}
}
s.writeObject(null);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
this.map = new VetoableChangeListenerMap();
ObjectInputStream.GetField fields = s.readFields();
@SuppressWarnings("unchecked")
Hashtable<String, VetoableChangeSupport> children = (Hashtable<String, VetoableChangeSupport>)fields.get("children", null);
this.source = fields.get("source", null);
fields.get("vetoableChangeSupportSerializedDataVersion", 2);
Object listenerOrNull;
while (null != (listenerOrNull = s.readObject())) {
this.map.add(null, (VetoableChangeListener)listenerOrNull);
}
if (children != null) {
for (Entry<String, VetoableChangeSupport> entry : children.entrySet()) {
for (VetoableChangeListener listener : entry.getValue().getVetoableChangeListeners()) {
this.map.add(entry.getKey(), listener);
}
}
}
}
/**
* The object to be provided as the "source" for any generated events.
*/
private Object source;
/**
* @serialField children Hashtable
* @serialField source Object
* @serialField vetoableChangeSupportSerializedDataVersion int
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("children", Hashtable.class),
new ObjectStreamField("source", Object.class),
new ObjectStreamField("vetoableChangeSupportSerializedDataVersion", Integer.TYPE)
};
/**
* Serialization version ID, so we're compatible with JDK 1.1
*/
static final long serialVersionUID = -5090210921595982017L;
/**
* This is a {@link ChangeListenerMap ChangeListenerMap} implementation
* that works with {@link VetoableChangeListener VetoableChangeListener} objects.
*/
private static final class VetoableChangeListenerMap extends ChangeListenerMap<VetoableChangeListener> {
private static final VetoableChangeListener[] EMPTY = {};
/**
* Creates an array of {@link VetoableChangeListener VetoableChangeListener} objects.
* This method uses the same instance of the empty array
* when {@code length} equals {@code 0}.
*
* @param length the array length
* @return an array with specified length
*/
@Override
protected VetoableChangeListener[] newArray(int length) {
return (0 < length)
? new VetoableChangeListener[length]
: EMPTY;
}
/**
* Creates a {@link VetoableChangeListenerProxy VetoableChangeListenerProxy}
* object for the specified property.
*
* @param name the name of the property to listen on
* @param listener the listener to process events
* @return a {@code VetoableChangeListenerProxy} object
*/
@Override
protected VetoableChangeListener newProxy(String name, VetoableChangeListener listener) {
return new VetoableChangeListenerProxy(name, listener);
}
/**
* {@inheritDoc}
*/
public final VetoableChangeListener extract(VetoableChangeListener listener) {
while (listener instanceof VetoableChangeListenerProxy) {
listener = ((VetoableChangeListenerProxy) listener).getListener();
}
return listener;
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 1996, 1998, 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;
/**
* Under some circumstances a bean may be run on servers where a GUI
* is not available. This interface can be used to query a bean to
* determine whether it absolutely needs a gui, and to advise the
* bean whether a GUI is available.
* <p>
* This interface is for expert developers, and is not needed
* for normal simple beans. To avoid confusing end-users we
* avoid using getXXX setXXX design patterns for these methods.
*/
public interface Visibility {
/**
* Determines whether this bean needs a GUI.
*
* @return True if the bean absolutely needs a GUI available in
* order to get its work done.
*/
boolean needsGui();
/**
* This method instructs the bean that it should not use the Gui.
*/
void dontUseGui();
/**
* This method instructs the bean that it is OK to use the Gui.
*/
void okToUseGui();
/**
* Determines whether this bean is avoiding using a GUI.
*
* @return true if the bean is currently avoiding use of the Gui.
* e.g. due to a call on dontUseGui().
*/
boolean avoidingGui();
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2013, 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 java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
/**
* Hash table based mapping, which uses weak references to store keys
* and reference-equality in place of object-equality to compare them.
* An entry will automatically be removed when its key is no longer
* in ordinary use. Both null values and the null key are supported.
* This class does not require additional synchronization.
* A thread-safety is provided by a fragile combination
* of synchronized blocks and volatile fields.
* Be very careful during editing!
*
* @see java.util.IdentityHashMap
* @see java.util.WeakHashMap
*/
abstract class WeakIdentityMap<T> {
private static final int MAXIMUM_CAPACITY = 1 << 30; // it MUST be a power of two
private static final Object NULL = new Object(); // special object for null key
private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
private volatile Entry<T>[] table = newTable(1<<3); // table's length MUST be a power of two
private int threshold = 6; // the next size value at which to resize
private int size = 0; // the number of key-value mappings
public T get(Object key) {
removeStaleEntries();
if (key == null) {
key = NULL;
}
int hash = key.hashCode();
Entry<T>[] table = this.table;
// unsynchronized search improves performance
// the null value does not mean that there are no needed entry
int index = getIndex(table, hash);
for (Entry<T> entry = table[index]; entry != null; entry = entry.next) {
if (entry.isMatched(key, hash)) {
return entry.value;
}
}
synchronized (NULL) {
// synchronized search improves stability
// we must create and add new value if there are no needed entry
index = getIndex(this.table, hash);
for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) {
if (entry.isMatched(key, hash)) {
return entry.value;
}
}
T value = create(key);
this.table[index] = new Entry<T>(key, hash, value, this.queue, this.table[index]);
if (++this.size >= this.threshold) {
if (this.table.length == MAXIMUM_CAPACITY) {
this.threshold = Integer.MAX_VALUE;
}
else {
removeStaleEntries();
table = newTable(this.table.length * 2);
transfer(this.table, table);
// If ignoring null elements and processing ref queue caused massive
// shrinkage, then restore old table. This should be rare, but avoids
// unbounded expansion of garbage-filled tables.
if (this.size >= this.threshold / 2) {
this.table = table;
this.threshold *= 2;
}
else {
transfer(table, this.table);
}
}
}
return value;
}
}
protected abstract T create(Object key);
private void removeStaleEntries() {
Object ref = this.queue.poll();
if (ref != null) {
synchronized (NULL) {
do {
@SuppressWarnings("unchecked")
Entry<T> entry = (Entry<T>) ref;
int index = getIndex(this.table, entry.hash);
Entry<T> prev = this.table[index];
Entry<T> current = prev;
while (current != null) {
Entry<T> next = current.next;
if (current == entry) {
if (prev == entry) {
this.table[index] = next;
}
else {
prev.next = next;
}
entry.value = null; // Help GC
entry.next = null; // Help GC
this.size--;
break;
}
prev = current;
current = next;
}
ref = this.queue.poll();
}
while (ref != null);
}
}
}
private void transfer(Entry<T>[] oldTable, Entry<T>[] newTable) {
for (int i = 0; i < oldTable.length; i++) {
Entry<T> entry = oldTable[i];
oldTable[i] = null;
while (entry != null) {
Entry<T> next = entry.next;
Object key = entry.get();
if (key == null) {
entry.value = null; // Help GC
entry.next = null; // Help GC
this.size--;
}
else {
int index = getIndex(newTable, entry.hash);
entry.next = newTable[index];
newTable[index] = entry;
}
entry = next;
}
}
}
@SuppressWarnings("unchecked")
private Entry<T>[] newTable(int length) {
return (Entry<T>[]) new Entry<?>[length];
}
private static int getIndex(Entry<?>[] table, int hash) {
return hash & (table.length - 1);
}
private static class Entry<T> extends WeakReference<Object> {
private final int hash;
private volatile T value;
private volatile Entry<T> next;
Entry(Object key, int hash, T value, ReferenceQueue<Object> queue, Entry<T> next) {
super(key, queue);
this.hash = hash;
this.value = value;
this.next = next;
}
boolean isMatched(Object key, int hash) {
return (this.hash == hash) && (key == get());
}
}
}

View File

@@ -0,0 +1,306 @@
/*
* Copyright (c) 2000, 2012, 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.decoder.DocumentHandler;
import java.io.Closeable;
import java.io.InputStream;
import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
/**
* The <code>XMLDecoder</code> class is used to read XML documents
* created using the <code>XMLEncoder</code> and is used just like
* the <code>ObjectInputStream</code>. For example, one can use
* the following fragment to read the first object defined
* in an XML document written by the <code>XMLEncoder</code>
* class:
* <pre>
* XMLDecoder d = new XMLDecoder(
* new BufferedInputStream(
* new FileInputStream("Test.xml")));
* Object result = d.readObject();
* d.close();
* </pre>
*
*<p>
* For more information you might also want to check out
* <a
href="http://java.sun.com/products/jfc/tsc/articles/persistence3">Long Term Persistence of JavaBeans Components: XML Schema</a>,
* an article in <em>The Swing Connection.</em>
* @see XMLEncoder
* @see java.io.ObjectInputStream
*
* @since 1.4
*
* @author Philip Milne
*/
public class XMLDecoder implements AutoCloseable {
private final AccessControlContext acc = AccessController.getContext();
private final DocumentHandler handler = new DocumentHandler();
private final InputSource input;
private Object owner;
private Object[] array;
private int index;
/**
* Creates a new input stream for reading archives
* created by the <code>XMLEncoder</code> class.
*
* @param in The underlying stream.
*
* @see XMLEncoder#XMLEncoder(java.io.OutputStream)
*/
public XMLDecoder(InputStream in) {
this(in, null);
}
/**
* Creates a new input stream for reading archives
* created by the <code>XMLEncoder</code> class.
*
* @param in The underlying stream.
* @param owner The owner of this stream.
*
*/
public XMLDecoder(InputStream in, Object owner) {
this(in, owner, null);
}
/**
* Creates a new input stream for reading archives
* created by the <code>XMLEncoder</code> class.
*
* @param in the underlying stream.
* @param owner the owner of this stream.
* @param exceptionListener the exception handler for the stream;
* if <code>null</code> the default exception listener will be used.
*/
public XMLDecoder(InputStream in, Object owner, ExceptionListener exceptionListener) {
this(in, owner, exceptionListener, null);
}
/**
* Creates a new input stream for reading archives
* created by the <code>XMLEncoder</code> class.
*
* @param in the underlying stream. <code>null</code> may be passed without
* error, though the resulting XMLDecoder will be useless
* @param owner the owner of this stream. <code>null</code> is a legal
* value
* @param exceptionListener the exception handler for the stream, or
* <code>null</code> to use the default
* @param cl the class loader used for instantiating objects.
* <code>null</code> indicates that the default class loader should
* be used
* @since 1.5
*/
public XMLDecoder(InputStream in, Object owner,
ExceptionListener exceptionListener, ClassLoader cl) {
this(new InputSource(in), owner, exceptionListener, cl);
}
/**
* Creates a new decoder to parse XML archives
* created by the {@code XMLEncoder} class.
* If the input source {@code is} is {@code null},
* no exception is thrown and no parsing is performed.
* This behavior is similar to behavior of other constructors
* that use {@code InputStream} as a parameter.
*
* @param is the input source to parse
*
* @since 1.7
*/
public XMLDecoder(InputSource is) {
this(is, null, null, null);
}
/**
* Creates a new decoder to parse XML archives
* created by the {@code XMLEncoder} class.
*
* @param is the input source to parse
* @param owner the owner of this decoder
* @param el the exception handler for the parser,
* or {@code null} to use the default exception handler
* @param cl the class loader used for instantiating objects,
* or {@code null} to use the default class loader
*
* @since 1.7
*/
private XMLDecoder(InputSource is, Object owner, ExceptionListener el, ClassLoader cl) {
this.input = is;
this.owner = owner;
setExceptionListener(el);
this.handler.setClassLoader(cl);
this.handler.setOwner(this);
}
/**
* This method closes the input stream associated
* with this stream.
*/
public void close() {
if (parsingComplete()) {
close(this.input.getCharacterStream());
close(this.input.getByteStream());
}
}
private void close(Closeable in) {
if (in != null) {
try {
in.close();
}
catch (IOException e) {
getExceptionListener().exceptionThrown(e);
}
}
}
private boolean parsingComplete() {
if (this.input == null) {
return false;
}
if (this.array == null) {
if ((this.acc == null) && (null != System.getSecurityManager())) {
throw new SecurityException("AccessControlContext is not set");
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
XMLDecoder.this.handler.parse(XMLDecoder.this.input);
return null;
}
}, this.acc);
this.array = this.handler.getObjects();
}
return true;
}
/**
* Sets the exception handler for this stream to <code>exceptionListener</code>.
* The exception handler is notified when this stream catches recoverable
* exceptions.
*
* @param exceptionListener The exception handler for this stream;
* if <code>null</code> the default exception listener will be used.
*
* @see #getExceptionListener
*/
public void setExceptionListener(ExceptionListener exceptionListener) {
if (exceptionListener == null) {
exceptionListener = Statement.defaultExceptionListener;
}
this.handler.setExceptionListener(exceptionListener);
}
/**
* Gets the exception handler for this stream.
*
* @return The exception handler for this stream.
* Will return the default exception listener if this has not explicitly been set.
*
* @see #setExceptionListener
*/
public ExceptionListener getExceptionListener() {
return this.handler.getExceptionListener();
}
/**
* Reads the next object from the underlying input stream.
*
* @return the next object read
*
* @throws ArrayIndexOutOfBoundsException if the stream contains no objects
* (or no more objects)
*
* @see XMLEncoder#writeObject
*/
public Object readObject() {
return (parsingComplete())
? this.array[this.index++]
: null;
}
/**
* Sets the owner of this decoder to <code>owner</code>.
*
* @param owner The owner of this decoder.
*
* @see #getOwner
*/
public void setOwner(Object owner) {
this.owner = owner;
}
/**
* Gets the owner of this decoder.
*
* @return The owner of this decoder.
*
* @see #setOwner
*/
public Object getOwner() {
return owner;
}
/**
* Creates a new handler for SAX parser
* that can be used to parse embedded XML archives
* created by the {@code XMLEncoder} class.
*
* The {@code owner} should be used if parsed XML document contains
* the method call within context of the &lt;java&gt; element.
* The {@code null} value may cause illegal parsing in such case.
* The same problem may occur, if the {@code owner} class
* does not contain expected method to call. See details <a
* href="http://java.sun.com/products/jfc/tsc/articles/persistence3/">here</a>.
*
* @param owner the owner of the default handler
* that can be used as a value of &lt;java&gt; element
* @param el the exception handler for the parser,
* or {@code null} to use the default exception handler
* @param cl the class loader used for instantiating objects,
* or {@code null} to use the default class loader
* @return an instance of {@code DefaultHandler} for SAX parser
*
* @since 1.7
*/
public static DefaultHandler createHandler(Object owner, ExceptionListener el, ClassLoader cl) {
DocumentHandler handler = new DocumentHandler();
handler.setOwner(owner);
handler.setExceptionListener(el);
handler.setClassLoader(cl);
return handler;
}
}

View File

@@ -0,0 +1,814 @@
/*
* Copyright (c) 2000, 2015, 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 java.io.*;
import java.util.*;
import java.lang.reflect.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
/**
* The <code>XMLEncoder</code> class is a complementary alternative to
* the <code>ObjectOutputStream</code> and can used to generate
* a textual representation of a <em>JavaBean</em> in the same
* way that the <code>ObjectOutputStream</code> can
* be used to create binary representation of <code>Serializable</code>
* objects. For example, the following fragment can be used to create
* a textual representation the supplied <em>JavaBean</em>
* and all its properties:
* <pre>
* XMLEncoder e = new XMLEncoder(
* new BufferedOutputStream(
* new FileOutputStream("Test.xml")));
* e.writeObject(new JButton("Hello, world"));
* e.close();
* </pre>
* Despite the similarity of their APIs, the <code>XMLEncoder</code>
* class is exclusively designed for the purpose of archiving graphs
* of <em>JavaBean</em>s as textual representations of their public
* properties. Like Java source files, documents written this way
* have a natural immunity to changes in the implementations of the classes
* involved. The <code>ObjectOutputStream</code> continues to be recommended
* for interprocess communication and general purpose serialization.
* <p>
* The <code>XMLEncoder</code> class provides a default denotation for
* <em>JavaBean</em>s in which they are represented as XML documents
* complying with version 1.0 of the XML specification and the
* UTF-8 character encoding of the Unicode/ISO 10646 character set.
* The XML documents produced by the <code>XMLEncoder</code> class are:
* <ul>
* <li>
* <em>Portable and version resilient</em>: they have no dependencies
* on the private implementation of any class and so, like Java source
* files, they may be exchanged between environments which may have
* different versions of some of the classes and between VMs from
* different vendors.
* <li>
* <em>Structurally compact</em>: The <code>XMLEncoder</code> class
* uses a <em>redundancy elimination</em> algorithm internally so that the
* default values of a Bean's properties are not written to the stream.
* <li>
* <em>Fault tolerant</em>: Non-structural errors in the file,
* caused either by damage to the file or by API changes
* made to classes in an archive remain localized
* so that a reader can report the error and continue to load the parts
* of the document which were not affected by the error.
* </ul>
* <p>
* Below is an example of an XML archive containing
* some user interface components from the <em>swing</em> toolkit:
* <pre>
* &lt;?xml version="1.0" encoding="UTF-8"?&gt;
* &lt;java version="1.0" class="java.beans.XMLDecoder"&gt;
* &lt;object class="javax.swing.JFrame"&gt;
* &lt;void property="name"&gt;
* &lt;string&gt;frame1&lt;/string&gt;
* &lt;/void&gt;
* &lt;void property="bounds"&gt;
* &lt;object class="java.awt.Rectangle"&gt;
* &lt;int&gt;0&lt;/int&gt;
* &lt;int&gt;0&lt;/int&gt;
* &lt;int&gt;200&lt;/int&gt;
* &lt;int&gt;200&lt;/int&gt;
* &lt;/object&gt;
* &lt;/void&gt;
* &lt;void property="contentPane"&gt;
* &lt;void method="add"&gt;
* &lt;object class="javax.swing.JButton"&gt;
* &lt;void property="label"&gt;
* &lt;string&gt;Hello&lt;/string&gt;
* &lt;/void&gt;
* &lt;/object&gt;
* &lt;/void&gt;
* &lt;/void&gt;
* &lt;void property="visible"&gt;
* &lt;boolean&gt;true&lt;/boolean&gt;
* &lt;/void&gt;
* &lt;/object&gt;
* &lt;/java&gt;
* </pre>
* The XML syntax uses the following conventions:
* <ul>
* <li>
* Each element represents a method call.
* <li>
* The "object" tag denotes an <em>expression</em> whose value is
* to be used as the argument to the enclosing element.
* <li>
* The "void" tag denotes a <em>statement</em> which will
* be executed, but whose result will not be used as an
* argument to the enclosing method.
* <li>
* Elements which contain elements use those elements as arguments,
* unless they have the tag: "void".
* <li>
* The name of the method is denoted by the "method" attribute.
* <li>
* XML's standard "id" and "idref" attributes are used to make
* references to previous expressions - so as to deal with
* circularities in the object graph.
* <li>
* The "class" attribute is used to specify the target of a static
* method or constructor explicitly; its value being the fully
* qualified name of the class.
* <li>
* Elements with the "void" tag are executed using
* the outer context as the target if no target is defined
* by a "class" attribute.
* <li>
* Java's String class is treated specially and is
* written &lt;string&gt;Hello, world&lt;/string&gt; where
* the characters of the string are converted to bytes
* using the UTF-8 character encoding.
* </ul>
* <p>
* Although all object graphs may be written using just these three
* tags, the following definitions are included so that common
* data structures can be expressed more concisely:
* <p>
* <ul>
* <li>
* The default method name is "new".
* <li>
* A reference to a java class is written in the form
* &lt;class&gt;javax.swing.JButton&lt;/class&gt;.
* <li>
* Instances of the wrapper classes for Java's primitive types are written
* using the name of the primitive type as the tag. For example, an
* instance of the <code>Integer</code> class could be written:
* &lt;int&gt;123&lt;/int&gt;. Note that the <code>XMLEncoder</code> class
* uses Java's reflection package in which the conversion between
* Java's primitive types and their associated "wrapper classes"
* is handled internally. The API for the <code>XMLEncoder</code> class
* itself deals only with <code>Object</code>s.
* <li>
* In an element representing a nullary method whose name
* starts with "get", the "method" attribute is replaced
* with a "property" attribute whose value is given by removing
* the "get" prefix and decapitalizing the result.
* <li>
* In an element representing a monadic method whose name
* starts with "set", the "method" attribute is replaced
* with a "property" attribute whose value is given by removing
* the "set" prefix and decapitalizing the result.
* <li>
* In an element representing a method named "get" taking one
* integer argument, the "method" attribute is replaced
* with an "index" attribute whose value the value of the
* first argument.
* <li>
* In an element representing a method named "set" taking two arguments,
* the first of which is an integer, the "method" attribute is replaced
* with an "index" attribute whose value the value of the
* first argument.
* <li>
* A reference to an array is written using the "array"
* tag. The "class" and "length" attributes specify the
* sub-type of the array and its length respectively.
* </ul>
*
*<p>
* For more information you might also want to check out
* <a
href="http://java.sun.com/products/jfc/tsc/articles/persistence4">Using XMLEncoder</a>,
* an article in <em>The Swing Connection.</em>
* @see XMLDecoder
* @see java.io.ObjectOutputStream
*
* @since 1.4
*
* @author Philip Milne
*/
public class XMLEncoder extends Encoder implements AutoCloseable {
private final CharsetEncoder encoder;
private final String charset;
private final boolean declaration;
private OutputStreamWriter out;
private Object owner;
private int indentation = 0;
private boolean internal = false;
private Map<Object, ValueData> valueToExpression;
private Map<Object, List<Statement>> targetToStatementList;
private boolean preambleWritten = false;
private NameGenerator nameGenerator;
private class ValueData {
public int refs = 0;
public boolean marked = false; // Marked -> refs > 0 unless ref was a target.
public String name = null;
public Expression exp = null;
}
/**
* Creates a new XML encoder to write out <em>JavaBeans</em>
* to the stream <code>out</code> using an XML encoding.
*
* @param out the stream to which the XML representation of
* the objects will be written
*
* @throws IllegalArgumentException
* if <code>out</code> is <code>null</code>
*
* @see XMLDecoder#XMLDecoder(InputStream)
*/
public XMLEncoder(OutputStream out) {
this(out, "UTF-8", true, 0);
}
/**
* Creates a new XML encoder to write out <em>JavaBeans</em>
* to the stream <code>out</code> using the given <code>charset</code>
* starting from the given <code>indentation</code>.
*
* @param out the stream to which the XML representation of
* the objects will be written
* @param charset the name of the requested charset;
* may be either a canonical name or an alias
* @param declaration whether the XML declaration should be generated;
* set this to <code>false</code>
* when embedding the contents in another XML document
* @param indentation the number of space characters to indent the entire XML document by
*
* @throws IllegalArgumentException
* if <code>out</code> or <code>charset</code> is <code>null</code>,
* or if <code>indentation</code> is less than 0
*
* @throws IllegalCharsetNameException
* if <code>charset</code> name is illegal
*
* @throws UnsupportedCharsetException
* if no support for the named charset is available
* in this instance of the Java virtual machine
*
* @throws UnsupportedOperationException
* if loaded charset does not support encoding
*
* @see Charset#forName(String)
*
* @since 1.7
*/
public XMLEncoder(OutputStream out, String charset, boolean declaration, int indentation) {
if (out == null) {
throw new IllegalArgumentException("the output stream cannot be null");
}
if (indentation < 0) {
throw new IllegalArgumentException("the indentation must be >= 0");
}
Charset cs = Charset.forName(charset);
this.encoder = cs.newEncoder();
this.charset = charset;
this.declaration = declaration;
this.indentation = indentation;
this.out = new OutputStreamWriter(out, cs.newEncoder());
valueToExpression = new IdentityHashMap<>();
targetToStatementList = new IdentityHashMap<>();
nameGenerator = new NameGenerator();
}
/**
* Sets the owner of this encoder to <code>owner</code>.
*
* @param owner The owner of this encoder.
*
* @see #getOwner
*/
public void setOwner(Object owner) {
this.owner = owner;
writeExpression(new Expression(this, "getOwner", new Object[0]));
}
/**
* Gets the owner of this encoder.
*
* @return The owner of this encoder.
*
* @see #setOwner
*/
public Object getOwner() {
return owner;
}
/**
* Write an XML representation of the specified object to the output.
*
* @param o The object to be written to the stream.
*
* @see XMLDecoder#readObject
*/
public void writeObject(Object o) {
if (internal) {
super.writeObject(o);
}
else {
writeStatement(new Statement(this, "writeObject", new Object[]{o}));
}
}
private List<Statement> statementList(Object target) {
List<Statement> list = targetToStatementList.get(target);
if (list == null) {
list = new ArrayList<>();
targetToStatementList.put(target, list);
}
return list;
}
private void mark(Object o, boolean isArgument) {
if (o == null || o == this) {
return;
}
ValueData d = getValueData(o);
Expression exp = d.exp;
// Do not mark liternal strings. Other strings, which might,
// for example, come from resource bundles should still be marked.
if (o.getClass() == String.class && exp == null) {
return;
}
// Bump the reference counts of all arguments
if (isArgument) {
d.refs++;
}
if (d.marked) {
return;
}
d.marked = true;
Object target = exp.getTarget();
mark(exp);
if (!(target instanceof Class)) {
statementList(target).add(exp);
// Pending: Why does the reference count need to
// be incremented here?
d.refs++;
}
}
private void mark(Statement stm) {
Object[] args = stm.getArguments();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
mark(arg, true);
}
mark(stm.getTarget(), stm instanceof Expression);
}
/**
* Records the Statement so that the Encoder will
* produce the actual output when the stream is flushed.
* <P>
* This method should only be invoked within the context
* of initializing a persistence delegate.
*
* @param oldStm The statement that will be written
* to the stream.
* @see java.beans.PersistenceDelegate#initialize
*/
public void writeStatement(Statement oldStm) {
// System.out.println("XMLEncoder::writeStatement: " + oldStm);
boolean internal = this.internal;
this.internal = true;
try {
super.writeStatement(oldStm);
/*
Note we must do the mark first as we may
require the results of previous values in
this context for this statement.
Test case is:
os.setOwner(this);
os.writeObject(this);
*/
mark(oldStm);
Object target = oldStm.getTarget();
if (target instanceof Field) {
String method = oldStm.getMethodName();
Object[] args = oldStm.getArguments();
if ((method == null) || (args == null)) {
}
else if (method.equals("get") && (args.length == 1)) {
target = args[0];
}
else if (method.equals("set") && (args.length == 2)) {
target = args[0];
}
}
statementList(target).add(oldStm);
}
catch (Exception e) {
getExceptionListener().exceptionThrown(new Exception("XMLEncoder: discarding statement " + oldStm, e));
}
this.internal = internal;
}
/**
* Records the Expression so that the Encoder will
* produce the actual output when the stream is flushed.
* <P>
* This method should only be invoked within the context of
* initializing a persistence delegate or setting up an encoder to
* read from a resource bundle.
* <P>
* For more information about using resource bundles with the
* XMLEncoder, see
* http://java.sun.com/products/jfc/tsc/articles/persistence4/#i18n
*
* @param oldExp The expression that will be written
* to the stream.
* @see java.beans.PersistenceDelegate#initialize
*/
public void writeExpression(Expression oldExp) {
boolean internal = this.internal;
this.internal = true;
Object oldValue = getValue(oldExp);
if (get(oldValue) == null || (oldValue instanceof String && !internal)) {
getValueData(oldValue).exp = oldExp;
super.writeExpression(oldExp);
}
this.internal = internal;
}
/**
* This method writes out the preamble associated with the
* XML encoding if it has not been written already and
* then writes out all of the values that been
* written to the stream since the last time <code>flush</code>
* was called. After flushing, all internal references to the
* values that were written to this stream are cleared.
*/
public void flush() {
if (!preambleWritten) { // Don't do this in constructor - it throws ... pending.
if (this.declaration) {
writeln("<?xml version=" + quote("1.0") +
" encoding=" + quote(this.charset) + "?>");
}
writeln("<java version=" + quote(System.getProperty("java.version")) +
" class=" + quote(XMLDecoder.class.getName()) + ">");
preambleWritten = true;
}
indentation++;
List<Statement> statements = statementList(this);
while (!statements.isEmpty()) {
Statement s = statements.remove(0);
if ("writeObject".equals(s.getMethodName())) {
outputValue(s.getArguments()[0], this, true);
}
else {
outputStatement(s, this, false);
}
}
indentation--;
Statement statement = getMissedStatement();
while (statement != null) {
outputStatement(statement, this, false);
statement = getMissedStatement();
}
try {
out.flush();
}
catch (IOException e) {
getExceptionListener().exceptionThrown(e);
}
clear();
}
void clear() {
super.clear();
nameGenerator.clear();
valueToExpression.clear();
targetToStatementList.clear();
}
Statement getMissedStatement() {
for (List<Statement> statements : this.targetToStatementList.values()) {
for (int i = 0; i < statements.size(); i++) {
if (Statement.class == statements.get(i).getClass()) {
return statements.remove(i);
}
}
}
return null;
}
/**
* This method calls <code>flush</code>, writes the closing
* postamble and then closes the output stream associated
* with this stream.
*/
public void close() {
flush();
writeln("</java>");
try {
out.close();
}
catch (IOException e) {
getExceptionListener().exceptionThrown(e);
}
}
private String quote(String s) {
return "\"" + s + "\"";
}
private ValueData getValueData(Object o) {
ValueData d = valueToExpression.get(o);
if (d == null) {
d = new ValueData();
valueToExpression.put(o, d);
}
return d;
}
/**
* Returns <code>true</code> if the argument,
* a Unicode code point, is valid in XML documents.
* Unicode characters fit into the low sixteen bits of a Unicode code point,
* and pairs of Unicode <em>surrogate characters</em> can be combined
* to encode Unicode code point in documents containing only Unicode.
* (The <code>char</code> datatype in the Java Programming Language
* represents Unicode characters, including unpaired surrogates.)
* <par>
* [2] Char ::= #x0009 | #x000A | #x000D
* | [#x0020-#xD7FF]
* | [#xE000-#xFFFD]
* | [#x10000-#x10ffff]
* </par>
*
* @param code the 32-bit Unicode code point being tested
* @return <code>true</code> if the Unicode code point is valid,
* <code>false</code> otherwise
*/
private static boolean isValidCharCode(int code) {
return (0x0020 <= code && code <= 0xD7FF)
|| (0x000A == code)
|| (0x0009 == code)
|| (0x000D == code)
|| (0xE000 <= code && code <= 0xFFFD)
|| (0x10000 <= code && code <= 0x10ffff);
}
private void writeln(String exp) {
try {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < indentation; i++) {
sb.append(' ');
}
sb.append(exp);
sb.append('\n');
this.out.write(sb.toString());
}
catch (IOException e) {
getExceptionListener().exceptionThrown(e);
}
}
private void outputValue(Object value, Object outer, boolean isArgument) {
if (value == null) {
writeln("<null/>");
return;
}
if (value instanceof Class) {
writeln("<class>" + ((Class)value).getName() + "</class>");
return;
}
ValueData d = getValueData(value);
if (d.exp != null) {
Object target = d.exp.getTarget();
String methodName = d.exp.getMethodName();
if (target == null || methodName == null) {
throw new NullPointerException((target == null ? "target" :
"methodName") + " should not be null");
}
if (isArgument && target instanceof Field && methodName.equals("get")) {
Field f = (Field) target;
if (Modifier.isStatic(f.getModifiers())) {
writeln("<object class=" + quote(f.getDeclaringClass().getName()) +
" field=" + quote(f.getName()) + "/>");
return;
}
}
Class<?> primitiveType = primitiveTypeFor(value.getClass());
if (primitiveType != null && target == value.getClass() &&
methodName.equals("new")) {
String primitiveTypeName = primitiveType.getName();
// Make sure that character types are quoted correctly.
if (primitiveType == Character.TYPE) {
char code = ((Character) value).charValue();
if (!isValidCharCode(code)) {
writeln(createString(code));
return;
}
value = quoteCharCode(code);
if (value == null) {
value = Character.valueOf(code);
}
}
writeln("<" + primitiveTypeName + ">" + value + "</" +
primitiveTypeName + ">");
return;
}
} else if (value instanceof String) {
writeln(createString((String) value));
return;
}
if (d.name != null) {
if (isArgument) {
writeln("<object idref=" + quote(d.name) + "/>");
}
else {
outputXML("void", " idref=" + quote(d.name), value);
}
}
else if (d.exp != null) {
outputStatement(d.exp, outer, isArgument);
}
}
private static String quoteCharCode(int code) {
switch(code) {
case '&': return "&amp;";
case '<': return "&lt;";
case '>': return "&gt;";
case '"': return "&quot;";
case '\'': return "&apos;";
case '\r': return "&#13;";
default: return null;
}
}
private static String createString(int code) {
return "<char code=\"#" + Integer.toString(code, 16) + "\"/>";
}
private String createString(String string) {
StringBuilder sb = new StringBuilder();
sb.append("<string>");
int index = 0;
while (index < string.length()) {
int point = string.codePointAt(index);
int count = Character.charCount(point);
if (isValidCharCode(point) && this.encoder.canEncode(string.substring(index, index + count))) {
String value = quoteCharCode(point);
if (value != null) {
sb.append(value);
} else {
sb.appendCodePoint(point);
}
index += count;
} else {
sb.append(createString(string.charAt(index)));
index++;
}
}
sb.append("</string>");
return sb.toString();
}
private void outputStatement(Statement exp, Object outer, boolean isArgument) {
Object target = exp.getTarget();
String methodName = exp.getMethodName();
if (target == null || methodName == null) {
throw new NullPointerException((target == null ? "target" :
"methodName") + " should not be null");
}
Object[] args = exp.getArguments();
boolean expression = exp.getClass() == Expression.class;
Object value = (expression) ? getValue((Expression)exp) : null;
String tag = (expression && isArgument) ? "object" : "void";
String attributes = "";
ValueData d = getValueData(value);
// Special cases for targets.
if (target == outer) {
}
else if (target == Array.class && methodName.equals("newInstance")) {
tag = "array";
attributes = attributes + " class=" + quote(((Class)args[0]).getName());
attributes = attributes + " length=" + quote(args[1].toString());
args = new Object[]{};
}
else if (target.getClass() == Class.class) {
attributes = attributes + " class=" + quote(((Class)target).getName());
}
else {
d.refs = 2;
if (d.name == null) {
getValueData(target).refs++;
List<Statement> statements = statementList(target);
if (!statements.contains(exp)) {
statements.add(exp);
}
outputValue(target, outer, false);
}
if (expression) {
outputValue(value, outer, isArgument);
}
return;
}
if (expression && (d.refs > 1)) {
String instanceName = nameGenerator.instanceName(value);
d.name = instanceName;
attributes = attributes + " id=" + quote(instanceName);
}
// Special cases for methods.
if ((!expression && methodName.equals("set") && args.length == 2 &&
args[0] instanceof Integer) ||
(expression && methodName.equals("get") && args.length == 1 &&
args[0] instanceof Integer)) {
attributes = attributes + " index=" + quote(args[0].toString());
args = (args.length == 1) ? new Object[]{} : new Object[]{args[1]};
}
else if ((!expression && methodName.startsWith("set") && args.length == 1) ||
(expression && methodName.startsWith("get") && args.length == 0)) {
if (3 < methodName.length()) {
attributes = attributes + " property=" +
quote(Introspector.decapitalize(methodName.substring(3)));
}
}
else if (!methodName.equals("new") && !methodName.equals("newInstance")) {
attributes = attributes + " method=" + quote(methodName);
}
outputXML(tag, attributes, value, args);
}
private void outputXML(String tag, String attributes, Object value, Object... args) {
List<Statement> statements = statementList(value);
// Use XML's short form when there is no body.
if (args.length == 0 && statements.size() == 0) {
writeln("<" + tag + attributes + "/>");
return;
}
writeln("<" + tag + attributes + ">");
indentation++;
for(int i = 0; i < args.length; i++) {
outputValue(args[i], null, true);
}
while (!statements.isEmpty()) {
Statement s = statements.remove(0);
outputStatement(s, value, false);
}
indentation--;
writeln("</" + tag + ">");
}
@SuppressWarnings("rawtypes")
static Class primitiveTypeFor(Class wrapper) {
if (wrapper == Boolean.class) return Boolean.TYPE;
if (wrapper == Byte.class) return Byte.TYPE;
if (wrapper == Character.class) return Character.TYPE;
if (wrapper == Short.class) return Short.TYPE;
if (wrapper == Integer.class) return Integer.TYPE;
if (wrapper == Long.class) return Long.TYPE;
if (wrapper == Float.class) return Float.TYPE;
if (wrapper == Double.class) return Double.TYPE;
if (wrapper == Void.class) return Void.TYPE;
return null;
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 1997, 2013, 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.beancontext;
import java.beans.DesignMode;
import java.beans.Visibility;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Locale;
/**
* <p>
* The BeanContext acts a logical hierarchical container for JavaBeans.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.Beans
* @see java.beans.beancontext.BeanContextChild
* @see java.beans.beancontext.BeanContextMembershipListener
* @see java.beans.PropertyChangeEvent
* @see java.beans.DesignMode
* @see java.beans.Visibility
* @see java.util.Collection
*/
@SuppressWarnings("rawtypes")
public interface BeanContext extends BeanContextChild, Collection, DesignMode, Visibility {
/**
* Instantiate the javaBean named as a
* child of this <code>BeanContext</code>.
* The implementation of the JavaBean is
* derived from the value of the beanName parameter,
* and is defined by the
* <code>java.beans.Beans.instantiate()</code> method.
*
* @return a javaBean named as a child of this
* <code>BeanContext</code>
* @param beanName The name of the JavaBean to instantiate
* as a child of this <code>BeanContext</code>
* @throws IOException if an IO problem occurs
* @throws ClassNotFoundException if the class identified
* by the beanName parameter is not found
*/
Object instantiateChild(String beanName) throws IOException, ClassNotFoundException;
/**
* Analagous to <code>java.lang.ClassLoader.getResourceAsStream()</code>,
* this method allows a <code>BeanContext</code> implementation
* to interpose behavior between the child <code>Component</code>
* and underlying <code>ClassLoader</code>.
*
* @param name the resource name
* @param bcc the specified child
* @return an <code>InputStream</code> for reading the resource,
* or <code>null</code> if the resource could not
* be found.
* @throws IllegalArgumentException if
* the resource is not valid
*/
InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException;
/**
* Analagous to <code>java.lang.ClassLoader.getResource()</code>, this
* method allows a <code>BeanContext</code> implementation to interpose
* behavior between the child <code>Component</code>
* and underlying <code>ClassLoader</code>.
*
* @param name the resource name
* @param bcc the specified child
* @return a <code>URL</code> for the named
* resource for the specified child
* @throws IllegalArgumentException
* if the resource is not valid
*/
URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException;
/**
* Adds the specified <code>BeanContextMembershipListener</code>
* to receive <code>BeanContextMembershipEvents</code> from
* this <code>BeanContext</code> whenever it adds
* or removes a child <code>Component</code>(s).
*
* @param bcml the BeanContextMembershipListener to be added
*/
void addBeanContextMembershipListener(BeanContextMembershipListener bcml);
/**
* Removes the specified <code>BeanContextMembershipListener</code>
* so that it no longer receives <code>BeanContextMembershipEvent</code>s
* when the child <code>Component</code>(s) are added or removed.
*
* @param bcml the <code>BeanContextMembershipListener</code>
* to be removed
*/
void removeBeanContextMembershipListener(BeanContextMembershipListener bcml);
/**
* This global lock is used by both <code>BeanContext</code>
* and <code>BeanContextServices</code> implementors
* to serialize changes in a <code>BeanContext</code>
* hierarchy and any service requests etc.
*/
public static final Object globalHierarchyLock = new Object();
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 1997, 2013, 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.beancontext;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.beans.PropertyVetoException;
import java.beans.beancontext.BeanContext;
/**
* <p>
* JavaBeans wishing to be nested within, and obtain a reference to their
* execution environment, or context, as defined by the BeanContext
* sub-interface shall implement this interface.
* </p>
* <p>
* Conformant BeanContexts shall as a side effect of adding a BeanContextChild
* object shall pass a reference to itself via the setBeanContext() method of
* this interface.
* </p>
* <p>
* Note that a BeanContextChild may refuse a change in state by throwing
* PropertyVetoedException in response.
* </p>
* <p>
* In order for persistence mechanisms to function properly on BeanContextChild
* instances across a broad variety of scenarios, implementing classes of this
* interface are required to define as transient, any or all fields, or
* instance variables, that may contain, or represent, references to the
* nesting BeanContext instance or other resources obtained
* from the BeanContext via any unspecified mechanisms.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.beancontext.BeanContext
* @see java.beans.PropertyChangeEvent
* @see java.beans.PropertyChangeListener
* @see java.beans.PropertyVetoException
* @see java.beans.VetoableChangeListener
*/
public interface BeanContextChild {
/**
* <p>
* Objects that implement this interface,
* shall fire a java.beans.PropertyChangeEvent, with parameters:
*
* propertyName "beanContext", oldValue (the previous nesting
* <code>BeanContext</code> instance, or <code>null</code>),
* newValue (the current nesting
* <code>BeanContext</code> instance, or <code>null</code>).
* <p>
* A change in the value of the nesting BeanContext property of this
* BeanContextChild may be vetoed by throwing the appropriate exception.
* </p>
* @param bc The <code>BeanContext</code> with which
* to associate this <code>BeanContextChild</code>.
* @throws PropertyVetoException if the
* addition of the specified <code>BeanContext</code> is refused.
*/
void setBeanContext(BeanContext bc) throws PropertyVetoException;
/**
* Gets the <code>BeanContext</code> associated
* with this <code>BeanContextChild</code>.
* @return the <code>BeanContext</code> associated
* with this <code>BeanContextChild</code>.
*/
BeanContext getBeanContext();
/**
* Adds a <code>PropertyChangeListener</code>
* to this <code>BeanContextChild</code>
* in order to receive a <code>PropertyChangeEvent</code>
* whenever the specified property has changed.
* @param name the name of the property to listen on
* @param pcl the <code>PropertyChangeListener</code> to add
*/
void addPropertyChangeListener(String name, PropertyChangeListener pcl);
/**
* Removes a <code>PropertyChangeListener</code> from this
* <code>BeanContextChild</code> so that it no longer
* receives <code>PropertyChangeEvents</code> when the
* specified property is changed.
*
* @param name the name of the property that was listened on
* @param pcl the <code>PropertyChangeListener</code> to remove
*/
void removePropertyChangeListener(String name, PropertyChangeListener pcl);
/**
* Adds a <code>VetoableChangeListener</code> to
* this <code>BeanContextChild</code>
* to receive events whenever the specified property changes.
* @param name the name of the property to listen on
* @param vcl the <code>VetoableChangeListener</code> to add
*/
void addVetoableChangeListener(String name, VetoableChangeListener vcl);
/**
* Removes a <code>VetoableChangeListener</code> from this
* <code>BeanContextChild</code> so that it no longer receives
* events when the specified property changes.
* @param name the name of the property that was listened on.
* @param vcl the <code>VetoableChangeListener</code> to remove.
*/
void removeVetoableChangeListener(String name, VetoableChangeListener vcl);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 1998, 2002, 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.beancontext;
import java.awt.Component;
/**
* <p>
* This interface is implemented by
* <code>BeanContextChildren</code> that have an AWT <code>Component</code>
* associated with them.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.beancontext.BeanContext
* @see java.beans.beancontext.BeanContextSupport
*/
public interface BeanContextChildComponentProxy {
/**
* Gets the <code>java.awt.Component</code> associated with
* this <code>BeanContextChild</code>.
* @return the AWT <code>Component</code> associated with
* this <code>BeanContextChild</code>
*/
Component getComponent();
}

View File

@@ -0,0 +1,377 @@
/*
* Copyright (c) 1998, 2013, 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.beancontext;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* <p>
* This is a general support class to provide support for implementing the
* BeanContextChild protocol.
*
* This class may either be directly subclassed, or encapsulated and delegated
* to in order to implement this interface for a given component.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.beancontext.BeanContext
* @see java.beans.beancontext.BeanContextServices
* @see java.beans.beancontext.BeanContextChild
*/
public class BeanContextChildSupport implements BeanContextChild, BeanContextServicesListener, Serializable {
static final long serialVersionUID = 6328947014421475877L;
/**
* construct a BeanContextChildSupport where this class has been
* subclassed in order to implement the JavaBean component itself.
*/
public BeanContextChildSupport() {
super();
beanContextChildPeer = this;
pcSupport = new PropertyChangeSupport(beanContextChildPeer);
vcSupport = new VetoableChangeSupport(beanContextChildPeer);
}
/**
* construct a BeanContextChildSupport where the JavaBean component
* itself implements BeanContextChild, and encapsulates this, delegating
* that interface to this implementation
* @param bcc the underlying bean context child
*/
public BeanContextChildSupport(BeanContextChild bcc) {
super();
beanContextChildPeer = (bcc != null) ? bcc : this;
pcSupport = new PropertyChangeSupport(beanContextChildPeer);
vcSupport = new VetoableChangeSupport(beanContextChildPeer);
}
/**
* Sets the <code>BeanContext</code> for
* this <code>BeanContextChildSupport</code>.
* @param bc the new value to be assigned to the <code>BeanContext</code>
* property
* @throws PropertyVetoException if the change is rejected
*/
public synchronized void setBeanContext(BeanContext bc) throws PropertyVetoException {
if (bc == beanContext) return;
BeanContext oldValue = beanContext;
BeanContext newValue = bc;
if (!rejectedSetBCOnce) {
if (rejectedSetBCOnce = !validatePendingSetBeanContext(bc)) {
throw new PropertyVetoException(
"setBeanContext() change rejected:",
new PropertyChangeEvent(beanContextChildPeer, "beanContext", oldValue, newValue)
);
}
try {
fireVetoableChange("beanContext",
oldValue,
newValue
);
} catch (PropertyVetoException pve) {
rejectedSetBCOnce = true;
throw pve; // re-throw
}
}
if (beanContext != null) releaseBeanContextResources();
beanContext = newValue;
rejectedSetBCOnce = false;
firePropertyChange("beanContext",
oldValue,
newValue
);
if (beanContext != null) initializeBeanContextResources();
}
/**
* Gets the nesting <code>BeanContext</code>
* for this <code>BeanContextChildSupport</code>.
* @return the nesting <code>BeanContext</code> for
* this <code>BeanContextChildSupport</code>.
*/
public synchronized BeanContext getBeanContext() { return beanContext; }
/**
* Add a PropertyChangeListener for a specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>name</code> or <code>pcl</code> is null, no exception is thrown
* and no action is taken.
*
* @param name The name of the property to listen on
* @param pcl The <code>PropertyChangeListener</code> to be added
*/
public void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
pcSupport.addPropertyChangeListener(name, pcl);
}
/**
* Remove a PropertyChangeListener for a specific property.
* If <code>pcl</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>name</code> is null, no exception is thrown
* and no action is taken.
* If <code>pcl</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param name The name of the property that was listened on
* @param pcl The PropertyChangeListener to be removed
*/
public void removePropertyChangeListener(String name, PropertyChangeListener pcl) {
pcSupport.removePropertyChangeListener(name, pcl);
}
/**
* Add a VetoableChangeListener for a specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>name</code> or <code>vcl</code> is null, no exception is thrown
* and no action is taken.
*
* @param name The name of the property to listen on
* @param vcl The <code>VetoableChangeListener</code> to be added
*/
public void addVetoableChangeListener(String name, VetoableChangeListener vcl) {
vcSupport.addVetoableChangeListener(name, vcl);
}
/**
* Removes a <code>VetoableChangeListener</code>.
* If <code>pcl</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>name</code> is null, no exception is thrown
* and no action is taken.
* If <code>vcl</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param name The name of the property that was listened on
* @param vcl The <code>VetoableChangeListener</code> to be removed
*/
public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) {
vcSupport.removeVetoableChangeListener(name, vcl);
}
/**
* A service provided by the nesting BeanContext has been revoked.
*
* Subclasses may override this method in order to implement their own
* behaviors.
* @param bcsre The <code>BeanContextServiceRevokedEvent</code> fired as a
* result of a service being revoked
*/
public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { }
/**
* A new service is available from the nesting BeanContext.
*
* Subclasses may override this method in order to implement their own
* behaviors
* @param bcsae The BeanContextServiceAvailableEvent fired as a
* result of a service becoming available
*
*/
public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { }
/**
* Gets the <tt>BeanContextChild</tt> associated with this
* <tt>BeanContextChildSupport</tt>.
*
* @return the <tt>BeanContextChild</tt> peer of this class
*/
public BeanContextChild getBeanContextChildPeer() { return beanContextChildPeer; }
/**
* Reports whether or not this class is a delegate of another.
*
* @return true if this class is a delegate of another
*/
public boolean isDelegated() { return !this.equals(beanContextChildPeer); }
/**
* Report a bound property update to any registered listeners. No event is
* fired if old and new are equal and non-null.
* @param name The programmatic name of the property that was changed
* @param oldValue The old value of the property
* @param newValue The new value of the property
*/
public void firePropertyChange(String name, Object oldValue, Object newValue) {
pcSupport.firePropertyChange(name, oldValue, newValue);
}
/**
* Report a vetoable property update to any registered listeners.
* If anyone vetos the change, then fire a new event
* reverting everyone to the old value and then rethrow
* the PropertyVetoException. <P>
*
* No event is fired if old and new are equal and non-null.
* <P>
* @param name The programmatic name of the property that is about to
* change
*
* @param oldValue The old value of the property
* @param newValue - The new value of the property
*
* @throws PropertyVetoException if the recipient wishes the property
* change to be rolled back.
*/
public void fireVetoableChange(String name, Object oldValue, Object newValue) throws PropertyVetoException {
vcSupport.fireVetoableChange(name, oldValue, newValue);
}
/**
* Called from setBeanContext to validate (or otherwise) the
* pending change in the nesting BeanContext property value.
* Returning false will cause setBeanContext to throw
* PropertyVetoException.
* @param newValue the new value that has been requested for
* the BeanContext property
* @return <code>true</code> if the change operation is to be vetoed
*/
public boolean validatePendingSetBeanContext(BeanContext newValue) {
return true;
}
/**
* This method may be overridden by subclasses to provide their own
* release behaviors. When invoked any resources held by this instance
* obtained from its current BeanContext property should be released
* since the object is no longer nested within that BeanContext.
*/
protected void releaseBeanContextResources() {
// do nothing
}
/**
* This method may be overridden by subclasses to provide their own
* initialization behaviors. When invoked any resources required by the
* BeanContextChild should be obtained from the current BeanContext.
*/
protected void initializeBeanContextResources() {
// do nothing
}
/**
* Write the persistence state of the object.
*/
private void writeObject(ObjectOutputStream oos) throws IOException {
/*
* don't serialize if we are delegated and the delegator is not also
* serializable.
*/
if (!equals(beanContextChildPeer) && !(beanContextChildPeer instanceof Serializable))
throw new IOException("BeanContextChildSupport beanContextChildPeer not Serializable");
else
oos.defaultWriteObject();
}
/**
* Restore a persistent object, must wait for subsequent setBeanContext()
* to fully restore any resources obtained from the new nesting
* BeanContext
*/
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
}
/*
* fields
*/
/**
* The <code>BeanContext</code> in which
* this <code>BeanContextChild</code> is nested.
*/
public BeanContextChild beanContextChildPeer;
/**
* The <tt>PropertyChangeSupport</tt> associated with this
* <tt>BeanContextChildSupport</tt>.
*/
protected PropertyChangeSupport pcSupport;
/**
* The <tt>VetoableChangeSupport</tt> associated with this
* <tt>BeanContextChildSupport</tt>.
*/
protected VetoableChangeSupport vcSupport;
/**
* The bean context.
*/
protected transient BeanContext beanContext;
/**
* A flag indicating that there has been
* at least one <code>PropertyChangeVetoException</code>
* thrown for the attempted setBeanContext operation.
*/
protected transient boolean rejectedSetBCOnce;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 1998, 2002, 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.beancontext;
import java.awt.Container;
/**
* <p>
* This interface is implemented by BeanContexts' that have an AWT Container
* associated with them.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.beancontext.BeanContext
* @see java.beans.beancontext.BeanContextSupport
*/
public interface BeanContextContainerProxy {
/**
* Gets the <code>java.awt.Container</code> associated
* with this <code>BeanContext</code>.
* @return the <code>java.awt.Container</code> associated
* with this <code>BeanContext</code>.
*/
Container getContainer();
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 1997, 2009, 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.beancontext;
import java.util.EventObject;
import java.beans.beancontext.BeanContext;
/**
* <p>
* <code>BeanContextEvent</code> is the abstract root event class
* for all events emitted
* from, and pertaining to the semantics of, a <code>BeanContext</code>.
* This class introduces a mechanism to allow the propagation of
* <code>BeanContextEvent</code> subclasses through a hierarchy of
* <code>BeanContext</code>s. The <code>setPropagatedFrom()</code>
* and <code>getPropagatedFrom()</code> methods allow a
* <code>BeanContext</code> to identify itself as the source
* of a propagated event.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
* @see java.beans.beancontext.BeanContext
*/
public abstract class BeanContextEvent extends EventObject {
private static final long serialVersionUID = 7267998073569045052L;
/**
* Contruct a BeanContextEvent
*
* @param bc The BeanContext source
*/
protected BeanContextEvent(BeanContext bc) {
super(bc);
}
/**
* Gets the <code>BeanContext</code> associated with this event.
* @return the <code>BeanContext</code> associated with this event.
*/
public BeanContext getBeanContext() { return (BeanContext)getSource(); }
/**
* Sets the <code>BeanContext</code> from which this event was propagated.
* @param bc the <code>BeanContext</code> from which this event
* was propagated
*/
public synchronized void setPropagatedFrom(BeanContext bc) {
propagatedFrom = bc;
}
/**
* Gets the <code>BeanContext</code> from which this event was propagated.
* @return the <code>BeanContext</code> from which this
* event was propagated
*/
public synchronized BeanContext getPropagatedFrom() {
return propagatedFrom;
}
/**
* Reports whether or not this event is
* propagated from some other <code>BeanContext</code>.
* @return <code>true</code> if propagated, <code>false</code>
* if not
*/
public synchronized boolean isPropagated() {
return propagatedFrom != null;
}
/*
* fields
*/
/**
* The <code>BeanContext</code> from which this event was propagated
*/
protected BeanContext propagatedFrom;
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 1997, 2013, 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.beancontext;
import java.util.EventObject;
import java.beans.beancontext.BeanContext;
import java.beans.beancontext.BeanContextEvent;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
/**
* A <code>BeanContextMembershipEvent</code> encapsulates
* the list of children added to, or removed from,
* the membership of a particular <code>BeanContext</code>.
* An instance of this event is fired whenever a successful
* add(), remove(), retainAll(), removeAll(), or clear() is
* invoked on a given <code>BeanContext</code> instance.
* Objects interested in receiving events of this type must
* implement the <code>BeanContextMembershipListener</code>
* interface, and must register their intent via the
* <code>BeanContext</code>'s
* <code>addBeanContextMembershipListener(BeanContextMembershipListener bcml)
* </code> method.
*
* @author Laurence P. G. Cable
* @since 1.2
* @see java.beans.beancontext.BeanContext
* @see java.beans.beancontext.BeanContextEvent
* @see java.beans.beancontext.BeanContextMembershipListener
*/
public class BeanContextMembershipEvent extends BeanContextEvent {
private static final long serialVersionUID = 3499346510334590959L;
/**
* Contruct a BeanContextMembershipEvent
*
* @param bc The BeanContext source
* @param changes The Children affected
* @throws NullPointerException if <CODE>changes</CODE> is <CODE>null</CODE>
*/
@SuppressWarnings("rawtypes")
public BeanContextMembershipEvent(BeanContext bc, Collection changes) {
super(bc);
if (changes == null) throw new NullPointerException(
"BeanContextMembershipEvent constructor: changes is null.");
children = changes;
}
/**
* Contruct a BeanContextMembershipEvent
*
* @param bc The BeanContext source
* @param changes The Children effected
* @exception NullPointerException if changes associated with this
* event are null.
*/
public BeanContextMembershipEvent(BeanContext bc, Object[] changes) {
super(bc);
if (changes == null) throw new NullPointerException(
"BeanContextMembershipEvent: changes is null.");
children = Arrays.asList(changes);
}
/**
* Gets the number of children affected by the notification.
* @return the number of children affected by the notification
*/
public int size() { return children.size(); }
/**
* Is the child specified affected by the event?
* @return <code>true</code> if affected, <code>false</code>
* if not
* @param child the object to check for being affected
*/
public boolean contains(Object child) {
return children.contains(child);
}
/**
* Gets the array of children affected by this event.
* @return the array of children affected
*/
public Object[] toArray() { return children.toArray(); }
/**
* Gets the array of children affected by this event.
* @return the array of children effected
*/
@SuppressWarnings("rawtypes")
public Iterator iterator() { return children.iterator(); }
/*
* fields
*/
/**
* The list of children affected by this
* event notification.
*/
@SuppressWarnings("rawtypes")
protected Collection children;
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 1997, 1999, 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.beancontext;
import java.beans.beancontext.BeanContextMembershipEvent;
import java.util.EventListener;
/**
* <p>
* Compliant BeanContexts fire events on this interface when the state of
* the membership of the BeanContext changes.
* </p>
*
* @author Laurence P. G. Cable
* @since 1.2
* @see java.beans.beancontext.BeanContext
*/
public interface BeanContextMembershipListener extends EventListener {
/**
* Called when a child or list of children is added to a
* <code>BeanContext</code> that this listener is registered with.
* @param bcme The <code>BeanContextMembershipEvent</code>
* describing the change that occurred.
*/
void childrenAdded(BeanContextMembershipEvent bcme);
/**
* Called when a child or list of children is removed
* from a <code>BeanContext</code> that this listener
* is registered with.
* @param bcme The <code>BeanContextMembershipEvent</code>
* describing the change that occurred.
*/
void childrenRemoved(BeanContextMembershipEvent bcme);
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 1998, 2002, 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.beancontext;
/**
* <p>
* This interface is implemented by a JavaBean that does
* not directly have a BeanContext(Child) associated with
* it (via implementing that interface or a subinterface thereof),
* but has a public BeanContext(Child) delegated from it.
* For example, a subclass of java.awt.Container may have a BeanContext
* associated with it that all Component children of that Container shall
* be contained within.
* </p>
* <p>
* An Object may not implement this interface and the
* BeanContextChild interface
* (or any subinterfaces thereof) they are mutually exclusive.
* </p>
* <p>
* Callers of this interface shall examine the return type in order to
* obtain a particular subinterface of BeanContextChild as follows:
* <code>
* BeanContextChild bcc = o.getBeanContextProxy();
*
* if (bcc instanceof BeanContext) {
* // ...
* }
* </code>
* or
* <code>
* BeanContextChild bcc = o.getBeanContextProxy();
* BeanContext bc = null;
*
* try {
* bc = (BeanContext)bcc;
* } catch (ClassCastException cce) {
* // cast failed, bcc is not an instanceof BeanContext
* }
* </code>
* </p>
* <p>
* The return value is a constant for the lifetime of the implementing
* instance
* </p>
* @author Laurence P. G. Cable
* @since 1.2
*
* @see java.beans.beancontext.BeanContextChild
* @see java.beans.beancontext.BeanContextChildSupport
*/
public interface BeanContextProxy {
/**
* Gets the <code>BeanContextChild</code> (or subinterface)
* associated with this object.
* @return the <code>BeanContextChild</code> (or subinterface)
* associated with this object
*/
BeanContextChild getBeanContextProxy();
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 1998, 2009, 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.beancontext;
import java.beans.beancontext.BeanContextChild;
import java.beans.beancontext.BeanContextEvent;
import java.beans.beancontext.BeanContextServices;
import java.util.Iterator;
/**
* <p>
* This event type is used by the BeanContextServicesListener in order to
* identify the service being registered.
* </p>
*/
public class BeanContextServiceAvailableEvent extends BeanContextEvent {
private static final long serialVersionUID = -5333985775656400778L;
/**
* Construct a <code>BeanContextAvailableServiceEvent</code>.
* @param bcs The context in which the service has become available
* @param sc A <code>Class</code> reference to the newly available service
*/
public BeanContextServiceAvailableEvent(BeanContextServices bcs, Class sc) {
super((BeanContext)bcs);
serviceClass = sc;
}
/**
* Gets the source as a reference of type <code>BeanContextServices</code>.
* @return The context in which the service has become available
*/
public BeanContextServices getSourceAsBeanContextServices() {
return (BeanContextServices)getBeanContext();
}
/**
* Gets the service class that is the subject of this notification.
* @return A <code>Class</code> reference to the newly available service
*/
public Class getServiceClass() { return serviceClass; }
/**
* Gets the list of service dependent selectors.
* @return the current selectors available from the service
*/
public Iterator getCurrentServiceSelectors() {
return ((BeanContextServices)getSource()).getCurrentServiceSelectors(serviceClass);
}
/*
* fields
*/
/**
* A <code>Class</code> reference to the newly available service
*/
protected Class serviceClass;
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 1998, 2004, 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.beancontext;
import java.util.Iterator;
/**
* <p>
* One of the primary functions of a BeanContext is to act a as rendezvous
* between JavaBeans, and BeanContextServiceProviders.
* </p>
* <p>
* A JavaBean nested within a BeanContext, may ask that BeanContext to
* provide an instance of a "service", based upon a reference to a Java
* Class object that represents that service.
* </p>
* <p>
* If such a service has been registered with the context, or one of its
* nesting context's, in the case where a context delegate to its context
* to satisfy a service request, then the BeanContextServiceProvider associated with
* the service is asked to provide an instance of that service.
* </p>
* <p>
* The ServcieProvider may always return the same instance, or it may
* construct a new instance for each request.
* </p>
*/
public interface BeanContextServiceProvider {
/**
* Invoked by <code>BeanContextServices</code>, this method
* requests an instance of a
* service from this <code>BeanContextServiceProvider</code>.
*
* @param bcs The <code>BeanContextServices</code> associated with this
* particular request. This parameter enables the
* <code>BeanContextServiceProvider</code> to distinguish service
* requests from multiple sources.
*
* @param requestor The object requesting the service
*
* @param serviceClass The service requested
*
* @param serviceSelector the service dependent parameter
* for a particular service, or <code>null</code> if not applicable.
*
* @return a reference to the requested service
*/
Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector);
/**
* Invoked by <code>BeanContextServices</code>,
* this method releases a nested <code>BeanContextChild</code>'s
* (or any arbitrary object associated with a
* <code>BeanContextChild</code>) reference to the specified service.
*
* @param bcs the <code>BeanContextServices</code> associated with this
* particular release request
*
* @param requestor the object requesting the service to be released
*
* @param service the service that is to be released
*/
public void releaseService(BeanContextServices bcs, Object requestor, Object service);
/**
* Invoked by <code>BeanContextServices</code>, this method
* gets the current service selectors for the specified service.
* A service selector is a service specific parameter,
* typical examples of which could include: a
* parameter to a constructor for the service implementation class,
* a value for a particular service's property, or a key into a
* map of existing implementations.
*
* @param bcs the <code>BeanContextServices</code> for this request
* @param serviceClass the specified service
* @return the current service selectors for the specified serviceClass
*/
Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass);
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 1998, 1999, 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.beancontext;
import java.beans.BeanInfo;
/**
* A BeanContextServiceProvider implementor who wishes to provide explicit
* information about the services their bean may provide shall implement a
* BeanInfo class that implements this BeanInfo subinterface and provides
* explicit information about the methods, properties, events, etc, of their
* services.
*/
public interface BeanContextServiceProviderBeanInfo extends BeanInfo {
/**
* Gets a <code>BeanInfo</code> array, one for each
* service class or interface statically available
* from this ServiceProvider.
* @return the <code>BeanInfo</code> array
*/
BeanInfo[] getServicesBeanInfo();
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 1998, 2009, 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.beancontext;
import java.beans.beancontext.BeanContextEvent;
import java.beans.beancontext.BeanContextServices;
/**
* <p>
* This event type is used by the
* <code>BeanContextServiceRevokedListener</code> in order to
* identify the service being revoked.
* </p>
*/
public class BeanContextServiceRevokedEvent extends BeanContextEvent {
private static final long serialVersionUID = -1295543154724961754L;
/**
* Construct a <code>BeanContextServiceEvent</code>.
* @param bcs the <code>BeanContextServices</code>
* from which this service is being revoked
* @param sc the service that is being revoked
* @param invalidate <code>true</code> for immediate revocation
*/
public BeanContextServiceRevokedEvent(BeanContextServices bcs, Class sc, boolean invalidate) {
super((BeanContext)bcs);
serviceClass = sc;
invalidateRefs = invalidate;
}
/**
* Gets the source as a reference of type <code>BeanContextServices</code>
* @return the <code>BeanContextServices</code> from which
* this service is being revoked
*/
public BeanContextServices getSourceAsBeanContextServices() {
return (BeanContextServices)getBeanContext();
}
/**
* Gets the service class that is the subject of this notification
* @return A <code>Class</code> reference to the
* service that is being revoked
*/
public Class getServiceClass() { return serviceClass; }
/**
* Checks this event to determine whether or not
* the service being revoked is of a particular class.
* @param service the service of interest (should be non-null)
* @return <code>true</code> if the service being revoked is of the
* same class as the specified service
*/
public boolean isServiceClass(Class service) {
return serviceClass.equals(service);
}
/**
* Reports if the current service is being forcibly revoked,
* in which case the references are now invalidated and unusable.
* @return <code>true</code> if current service is being forcibly revoked
*/
public boolean isCurrentServiceInvalidNow() { return invalidateRefs; }
/**
* fields
*/
/**
* A <code>Class</code> reference to the service that is being revoked.
*/
protected Class serviceClass;
private boolean invalidateRefs;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 1998, 2013, 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.beancontext;
import java.beans.beancontext.BeanContextServiceRevokedEvent;
import java.util.EventListener;
/**
* The listener interface for receiving
* <code>BeanContextServiceRevokedEvent</code> objects. A class that is
* interested in processing a <code>BeanContextServiceRevokedEvent</code>
* implements this interface.
*/
public interface BeanContextServiceRevokedListener extends EventListener {
/**
* The service named has been revoked. getService requests for
* this service will no longer be satisfied.
* @param bcsre the <code>BeanContextServiceRevokedEvent</code> received
* by this listener.
*/
void serviceRevoked(BeanContextServiceRevokedEvent bcsre);
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 1998, 2013, 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.beancontext;
import java.util.Iterator;
import java.util.TooManyListenersException;
import java.beans.beancontext.BeanContext;
import java.beans.beancontext.BeanContextServiceProvider;
import java.beans.beancontext.BeanContextServicesListener;
/**
* <p>
* The BeanContextServices interface provides a mechanism for a BeanContext
* to expose generic "services" to the BeanContextChild objects within.
* </p>
*/
public interface BeanContextServices extends BeanContext, BeanContextServicesListener {
/**
* Adds a service to this BeanContext.
* <code>BeanContextServiceProvider</code>s call this method
* to register a particular service with this context.
* If the service has not previously been added, the
* <code>BeanContextServices</code> associates
* the service with the <code>BeanContextServiceProvider</code> and
* fires a <code>BeanContextServiceAvailableEvent</code> to all
* currently registered <code>BeanContextServicesListeners</code>.
* The method then returns <code>true</code>, indicating that
* the addition of the service was successful.
* If the given service has already been added, this method
* simply returns <code>false</code>.
* @param serviceClass the service to add
* @param serviceProvider the <code>BeanContextServiceProvider</code>
* associated with the service
* @return true if the service was successful added, false otherwise
*/
boolean addService(Class serviceClass, BeanContextServiceProvider serviceProvider);
/**
* BeanContextServiceProviders wishing to remove
* a currently registered service from this context
* may do so via invocation of this method. Upon revocation of
* the service, the <code>BeanContextServices</code> fires a
* <code>BeanContextServiceRevokedEvent</code> to its
* list of currently registered
* <code>BeanContextServiceRevokedListeners</code> and
* <code>BeanContextServicesListeners</code>.
* @param serviceClass the service to revoke from this BeanContextServices
* @param serviceProvider the BeanContextServiceProvider associated with
* this particular service that is being revoked
* @param revokeCurrentServicesNow a value of <code>true</code>
* indicates an exceptional circumstance where the
* <code>BeanContextServiceProvider</code> or
* <code>BeanContextServices</code> wishes to immediately
* terminate service to all currently outstanding references
* to the specified service.
*/
void revokeService(Class serviceClass, BeanContextServiceProvider serviceProvider, boolean revokeCurrentServicesNow);
/**
* Reports whether or not a given service is
* currently available from this context.
* @param serviceClass the service in question
* @return true if the service is available
*/
boolean hasService(Class serviceClass);
/**
* A <code>BeanContextChild</code>, or any arbitrary object
* associated with a <code>BeanContextChild</code>, may obtain
* a reference to a currently registered service from its
* nesting <code>BeanContextServices</code>
* via invocation of this method. When invoked, this method
* gets the service by calling the getService() method on the
* underlying <code>BeanContextServiceProvider</code>.
* @param child the <code>BeanContextChild</code>
* associated with this request
* @param requestor the object requesting the service
* @param serviceClass class of the requested service
* @param serviceSelector the service dependent parameter
* @param bcsrl the
* <code>BeanContextServiceRevokedListener</code> to notify
* if the service should later become revoked
* @throws TooManyListenersException if there are too many listeners
* @return a reference to this context's named
* Service as requested or <code>null</code>
*/
Object getService(BeanContextChild child, Object requestor, Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException;
/**
* Releases a <code>BeanContextChild</code>'s
* (or any arbitrary object associated with a BeanContextChild)
* reference to the specified service by calling releaseService()
* on the underlying <code>BeanContextServiceProvider</code>.
* @param child the <code>BeanContextChild</code>
* @param requestor the requestor
* @param service the service
*/
void releaseService(BeanContextChild child, Object requestor, Object service);
/**
* Gets the currently available services for this context.
* @return an <code>Iterator</code> consisting of the
* currently available services
*/
Iterator getCurrentServiceClasses();
/**
* Gets the list of service dependent service parameters
* (Service Selectors) for the specified service, by
* calling getCurrentServiceSelectors() on the
* underlying BeanContextServiceProvider.
* @param serviceClass the specified service
* @return the currently available service selectors
* for the named serviceClass
*/
Iterator getCurrentServiceSelectors(Class serviceClass);
/**
* Adds a <code>BeanContextServicesListener</code> to this BeanContext
* @param bcsl the <code>BeanContextServicesListener</code> to add
*/
void addBeanContextServicesListener(BeanContextServicesListener bcsl);
/**
* Removes a <code>BeanContextServicesListener</code>
* from this <code>BeanContext</code>
* @param bcsl the <code>BeanContextServicesListener</code>
* to remove from this context
*/
void removeBeanContextServicesListener(BeanContextServicesListener bcsl);
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 1998, 1999, 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.beancontext;
import java.beans.beancontext.BeanContextServiceAvailableEvent;
import java.beans.beancontext.BeanContextServiceRevokedEvent;
import java.beans.beancontext.BeanContextServiceRevokedListener;
/**
* The listener interface for receiving
* <code>BeanContextServiceAvailableEvent</code> objects.
* A class that is interested in processing a
* <code>BeanContextServiceAvailableEvent</code> implements this interface.
*/
public interface BeanContextServicesListener extends BeanContextServiceRevokedListener {
/**
* The service named has been registered. getService requests for
* this service may now be made.
* @param bcsae the <code>BeanContextServiceAvailableEvent</code>
*/
void serviceAvailable(BeanContextServiceAvailableEvent bcsae);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff