summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/beans
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/beans
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/beans')
-rw-r--r--libjava/classpath/java/beans/AppletInitializer.java61
-rw-r--r--libjava/classpath/java/beans/BeanDescriptor.java89
-rw-r--r--libjava/classpath/java/beans/BeanInfo.java181
-rw-r--r--libjava/classpath/java/beans/Beans.java368
-rw-r--r--libjava/classpath/java/beans/ConstructorProperties.java72
-rw-r--r--libjava/classpath/java/beans/Customizer.java86
-rw-r--r--libjava/classpath/java/beans/DefaultPersistenceDelegate.java211
-rw-r--r--libjava/classpath/java/beans/DesignMode.java95
-rw-r--r--libjava/classpath/java/beans/Encoder.java433
-rw-r--r--libjava/classpath/java/beans/EventHandler.java604
-rw-r--r--libjava/classpath/java/beans/EventSetDescriptor.java763
-rw-r--r--libjava/classpath/java/beans/ExceptionListener.java57
-rw-r--r--libjava/classpath/java/beans/Expression.java138
-rw-r--r--libjava/classpath/java/beans/FeatureDescriptor.java232
-rw-r--r--libjava/classpath/java/beans/IndexedPropertyChangeEvent.java81
-rw-r--r--libjava/classpath/java/beans/IndexedPropertyDescriptor.java421
-rw-r--r--libjava/classpath/java/beans/IntrospectionException.java67
-rw-r--r--libjava/classpath/java/beans/Introspector.java705
-rw-r--r--libjava/classpath/java/beans/MethodDescriptor.java87
-rw-r--r--libjava/classpath/java/beans/ParameterDescriptor.java52
-rw-r--r--libjava/classpath/java/beans/PersistenceDelegate.java90
-rw-r--r--libjava/classpath/java/beans/PropertyChangeEvent.java189
-rw-r--r--libjava/classpath/java/beans/PropertyChangeListener.java61
-rw-r--r--libjava/classpath/java/beans/PropertyChangeListenerProxy.java102
-rw-r--r--libjava/classpath/java/beans/PropertyChangeSupport.java545
-rw-r--r--libjava/classpath/java/beans/PropertyDescriptor.java665
-rw-r--r--libjava/classpath/java/beans/PropertyEditor.java209
-rw-r--r--libjava/classpath/java/beans/PropertyEditorManager.java216
-rw-r--r--libjava/classpath/java/beans/PropertyEditorSupport.java265
-rw-r--r--libjava/classpath/java/beans/PropertyVetoException.java85
-rw-r--r--libjava/classpath/java/beans/SimpleBeanInfo.java145
-rw-r--r--libjava/classpath/java/beans/Statement.java386
-rw-r--r--libjava/classpath/java/beans/TODO4
-rw-r--r--libjava/classpath/java/beans/VetoableChangeListener.java73
-rw-r--r--libjava/classpath/java/beans/VetoableChangeListenerProxy.java102
-rw-r--r--libjava/classpath/java/beans/VetoableChangeSupport.java532
-rw-r--r--libjava/classpath/java/beans/Visibility.java85
-rw-r--r--libjava/classpath/java/beans/XMLDecoder.java307
-rw-r--r--libjava/classpath/java/beans/XMLEncoder.java267
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContext.java272
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextChild.java174
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java60
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java381
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java63
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextEvent.java110
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java114
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java70
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextProxy.java65
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java97
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java138
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java60
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java112
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java62
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServices.java216
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java56
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java896
-rw-r--r--libjava/classpath/java/beans/beancontext/BeanContextSupport.java1079
-rw-r--r--libjava/classpath/java/beans/beancontext/package.html46
-rw-r--r--libjava/classpath/java/beans/package.html46
59 files changed, 13248 insertions, 0 deletions
diff --git a/libjava/classpath/java/beans/AppletInitializer.java b/libjava/classpath/java/beans/AppletInitializer.java
new file mode 100644
index 000000000..3bc2534e1
--- /dev/null
+++ b/libjava/classpath/java/beans/AppletInitializer.java
@@ -0,0 +1,61 @@
+/* java.beans.AppletInitializer
+ Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+import java.applet.Applet;
+import java.beans.beancontext.BeanContext;
+
+
+/** This interface is a mechanism for the initialization of a Java
+ * Bean that is also an Applet. It is used by
+ * <code>Beans.instantiate()</code>.
+ *
+ * @author Tom Tromey (tromey@redhat.com)
+ * @since 1.2
+ */
+public interface AppletInitializer
+{
+ /** Activate the applet. */
+ void activate (Applet applet);
+
+ /** This method will be called by <code>Beans.instantiate()</code>
+ * to associated the new Applet with its AppletContext, AppletStub,
+ * and Container.
+ */
+ void initialize (Applet applet, BeanContext context);
+}
diff --git a/libjava/classpath/java/beans/BeanDescriptor.java b/libjava/classpath/java/beans/BeanDescriptor.java
new file mode 100644
index 000000000..6795d91b3
--- /dev/null
+++ b/libjava/classpath/java/beans/BeanDescriptor.java
@@ -0,0 +1,89 @@
+/* java.beans.BeanDescriptor
+ Copyright (C) 1998, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ ** BeanDescriptor describes general information about a Bean, plus
+ ** stores the Bean's Class and it's customizer's Class.<P>
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 31 May 1998
+ **/
+
+public class BeanDescriptor extends FeatureDescriptor {
+ Class<?> beanClass;
+ Class<?> customizerClass;
+
+ /** Create a new BeanDescriptor with the given beanClass and
+ ** no customizer class.
+ ** @param beanClass the class of the Bean.
+ **/
+ public BeanDescriptor(Class<?> beanClass) {
+ this(beanClass,null);
+ }
+
+ /** Create a new BeanDescriptor with the given bean class and
+ ** customizer class.
+ ** @param beanClass the class of the Bean.
+ ** @param customizerClass the class of the Bean's Customizer.
+ **/
+ public BeanDescriptor(Class<?> beanClass, Class<?> customizerClass) {
+ this.beanClass = beanClass;
+ this.customizerClass = customizerClass;
+
+ // Set the FeatureDescriptor programmatic name.
+ String name = beanClass.getName();
+ int lastInd = name.lastIndexOf('.');
+ if (lastInd != -1)
+ name = name.substring(lastInd + 1);
+
+ setName(name);
+ }
+
+ /** Get the Bean's class. **/
+ public Class<?> getBeanClass() {
+ return beanClass;
+ }
+
+ /** Get the Bean's customizer's class. **/
+ public Class<?> getCustomizerClass() {
+ return customizerClass;
+ }
+}
diff --git a/libjava/classpath/java/beans/BeanInfo.java b/libjava/classpath/java/beans/BeanInfo.java
new file mode 100644
index 000000000..3c9bf1bcd
--- /dev/null
+++ b/libjava/classpath/java/beans/BeanInfo.java
@@ -0,0 +1,181 @@
+/* java.beans.BeanInfo
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ ** BeanInfo can be implemented in order to provide explicit information to the Introspector.
+ **
+ ** When you write a BeanInfo class, you implement this interface
+ ** and provide explicit information by returning a non-null
+ ** value from the appropriate method. If you wish the
+ ** Introspector to determine certain information in the normal
+ ** way, just return null (or in the case of int methods, return
+ ** -1). There is a class called SimpleBeanInfo which returns
+ ** null from all methods, which you may extend and only
+ ** override the methods you wish to override.<P>
+ **
+ ** When you have written the class, give it the name
+ ** <CODE>&lt;Bean Class Name&gt;BeanInfo</CODE> and place it in
+ ** the same package as the Bean, or in the bean info search path
+ ** (see Introspector for information on search paths).<P>
+ **
+ ** A simple note about the way the Introspector interacts with
+ ** BeanInfo. Introspectors look at a Bean class and determine
+ ** if there is a BeanInfo class with it. If there is not a
+ ** BeanInfo class, it will behave as if the BeanInfo class
+ ** provided was a SimpleBeanInfo class (i.e. it will determine
+ ** all information automatically).<P>If there is a BeanInfo
+ ** class, then any methods that do *not* return null are
+ ** regarded as providing definitive information about the class
+ ** and all of its superclasses for those information types.
+ ** Even if a parent BeanInfo class explicitly returns that
+ ** information, it will not be used.
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 28 Jul 1998
+ **/
+
+public interface BeanInfo {
+ /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/
+ int ICON_COLOR_16x16 = 1;
+ /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/
+ int ICON_COLOR_32x32 = 2;
+ /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/
+ int ICON_MONO_16x16 = 3;
+ /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/
+ int ICON_MONO_32x32 = 4;
+
+ /** Get the general description of this Bean type.
+ ** @return the BeanDescriptor for the Bean, or null if
+ ** the BeanDescriptor should be obtained by
+ ** Introspection.
+ **/
+ BeanDescriptor getBeanDescriptor();
+
+ /** Get the events this Bean type fires.
+ ** @return the EventDescriptors representing events this
+ ** Bean fires. Returns <CODE>null</CODE> if the
+ ** events are to be acquired by Introspection.
+ **/
+ EventSetDescriptor[] getEventSetDescriptors();
+
+ /** Get the "default" event, basically the one a RAD tool
+ ** user is most likely to select.
+ ** @return the index into the getEventSetDescriptors()
+ ** that the user is most likely to use. Returns
+ ** <CODE>-1</CODE> if there is no default event.
+ **/
+ int getDefaultEventIndex();
+
+ /** Get the properties (get/set method pairs) this Bean
+ ** type supports.
+ ** @return the PropertyDescriptors representing the
+ ** properties this Bean type supports.
+ ** Returns <CODE>null</CODE> if the properties
+ ** are to be obtained by Introspection.
+ **/
+ PropertyDescriptor[] getPropertyDescriptors();
+
+ /** Get the "default" property, basically the one a RAD
+ ** tool user is most likely to select.
+ ** @return the index into the getPropertyDescriptors()
+ ** that the user is most likely to use. Returns
+ ** <CODE>-1</CODE> if there is no default event.
+ **/
+ int getDefaultPropertyIndex();
+
+ /** Get the methods this Bean type supports.
+ ** @return the MethodDescriptors representing the
+ ** methods this Bean type supports. Returns
+ ** <CODE>null</CODE> if the methods are to be
+ ** obtained by Introspection.
+ **/
+ MethodDescriptor[] getMethodDescriptors();
+
+ /** Get additional BeanInfos representing this Bean.
+ ** In this version of JavaBeans, this method is used so
+ ** that space and time can be saved by reading a BeanInfo
+ ** for each class in the hierarchy (super, super(super),
+ ** and so on).<P>
+ **
+ ** The order of precedence when two pieces of BeanInfo
+ ** conflict (such as two PropertyDescriptors that have
+ ** the same name), in order from highest precedence to
+ ** lowest, is:
+ ** <OL>
+ ** <LI>This BeanInfo object.</LI>
+ ** <LI><CODE>getAdditionalBeanInfo()[getAdditionalBeanInfo().length]</CODE></LI>
+ ** <LI> ... </LI>
+ ** <LI><CODE>getAdditionalBeanInfo()[1]</CODE></LI>
+ ** <LI><CODE>getAdditionalBeanInfo()[0]</CODE></LI>
+ ** </OL><P>
+ **
+ ** <STRONG>Spec Note:</STRONG> It is possible that
+ ** returning <CODE>null</CODE> from this method could
+ ** stop Introspection in its tracks, but it is unclear
+ ** from the spec whether this is the case.
+ **
+ ** @return additional BeanInfos representing this Bean.
+ ** <CODE>null</CODE> may be returned (see Spec
+ ** Note, above).
+ **/
+ BeanInfo[] getAdditionalBeanInfo();
+
+ /** Get a visual icon for this Bean.
+ ** A Bean does not have to support icons, and if it does
+ ** support icons, it does not have to support every single
+ ** type. Sun recommends that if you only support one
+ ** type, you support 16x16 color. Sun also notes that you
+ ** should try to use a type (like GIF) that allows for
+ ** transparent pixels, so that the background of the RAD
+ ** tool can show through.<P>
+ **
+ ** <STRONG>Spec Note:</STRONG> If you do not support the
+ ** type of icon that is being asked for, but you do
+ ** support another type, it is unclear whether you should
+ ** return the other type or not. I would presume not.
+ **
+ ** @param iconType the type of icon to get (see the
+ ** ICON_* constants in this class).
+ ** @return the icon, or null if that type of icon is
+ ** unsupported by this Bean.
+ **/
+ java.awt.Image getIcon(int iconType);
+}
diff --git a/libjava/classpath/java/beans/Beans.java b/libjava/classpath/java/beans/Beans.java
new file mode 100644
index 000000000..3066be7a5
--- /dev/null
+++ b/libjava/classpath/java/beans/Beans.java
@@ -0,0 +1,368 @@
+/* java.beans.Beans
+ Copyright (C) 1998, 1999, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+import gnu.java.beans.DummyAppletStub;
+import gnu.java.io.ClassLoaderObjectInputStream;
+
+import java.applet.Applet;
+import java.beans.beancontext.BeanContext;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.URL;
+
+/**
+ * <code>Beans</code> provides some helper methods that allow the basic
+ * operations of Bean-ness.
+ *
+ * @author John Keiser
+ * @author Robert Schuster
+ *
+ * @since 1.1
+ * @status updated to 1.4
+ *
+ */
+public class Beans
+{
+ static boolean designTime = false;
+ static boolean guiAvailable = true;
+
+ /**
+ * Once again, we have a java.beans class with only
+ * static methods that can be instantiated. When
+ * will the madness end? :)
+ */
+ public Beans()
+ {
+ // Does intentionally nothing here.
+ }
+
+ /** Creates a bean.
+ * <p>This is a convenience method that calls <code>instantiate(cl, beanName, null, null)</code>.</p>
+ *
+ * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer)
+ * @param cl ClassLoader to be used or <code>null</code> for the system classloader.
+ * @param beanName Name of a serialized bean or class name.
+ * @return A newly created bean.
+ * @throws IOException If access of an IO resource failed.
+ * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class.
+ */
+ public static Object instantiate(ClassLoader cl, String beanName)
+ throws IOException, ClassNotFoundException
+ {
+ return instantiate(cl, beanName, null, null);
+ }
+
+ /** Creates a bean.
+ *
+ * <p>This is a convenience method that calls <code>instantiate(cl, beanName, beanContext, null)</code>.</p>
+ *
+ * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer)
+ * @param cl ClassLoader to be used or <code>null</code> for the system classloader.
+ * @param beanName Name of a serialized bean or class name.
+ * @param beanContext Context to which the newly created Bean should be added.
+ * @return A newly created bean.
+ * @throws IOException If access of an IO resource failed.
+ * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class.
+ */
+ public static Object instantiate(
+ ClassLoader cl,
+ String beanName,
+ BeanContext beanContext)
+ throws IOException, ClassNotFoundException
+ {
+ return instantiate(cl, beanName, beanContext, null);
+ }
+
+ /** Instantiates a bean according to Beans 1.0.
+ *
+ * <p>In Beans 1.0 the instantiation scheme is as follows:</p>
+ * <p>The name should be dot-separated (e.g "place.for.beans.myBean") and indicate either a
+ * serialized object or a class name. In the first case all dots in the name are replaced with
+ * slashes ('/') and ".ser" is appended ("place.for.beans.myBean" becomes "place/for/beans/myBean.ser").
+ * The bean is then loaded as an application or system resource depending on whether a
+ * <code>ClassLoader</code> was provided.</p>
+ *
+ * <p>If no such resource exists or if it contains no bean the name is interpreted as a class name of
+ * which an instance is then created.</p>
+ *
+ * <p>If a <code>BeanContext</code> instance is available the created bean is added to it.</p>
+ *
+ * <p>If the created Bean is an <code>Applet</code> or subclass and an <code>AppletInitializer</code>
+ * instance is available the applet is initialized and afterwards activated using the initializer. Additionally
+ * every instantiated <code>Applet</code> bean is initialized using the {@link Applet.init} method.
+ * Furthermore every applet gets a default <code>AppletStub</code>. The <code>Applet</code>'s
+ * document base is the location of the ".ser" file if it was deserialized or the location of its class
+ * file if it was instantiated.</p>
+ *
+ * <p>A <code>ClassNotFoundException</code> is not only thrown when a class name was unknown
+ * but even when the class has public no-argument constructor
+ * (<code>IllegalAccessException</code> is wrapped) or an exception is thrown while
+ * invoking such a constructor (causing exception is wrapped).</p>
+ *
+ * @param cl ClassLoader to be used or <code>null</code> for the system classloader.
+ * @param beanName Name of a serialized bean or class name.
+ * @param beanContext Context to which the newly created Bean should be added.
+ * @param initializer The AppletInitializer which is used for initializing <code>Applet</code> beans.
+ * @return A newly created bean.
+ * @throws IOException If access of an IO resource failed.
+ * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class.
+ */
+ public static Object instantiate(
+ ClassLoader cl,
+ String beanName,
+ BeanContext beanContext,
+ AppletInitializer initializer)
+ throws IOException, ClassNotFoundException
+ {
+ Object bean = null;
+ URL beanLocation = null;
+ URL classLocation = null;
+
+ // Converts bean name into a resource name (eg. "a.b.c" -> "a/b/c").
+ String resourceName = beanName.replace('.', '/');
+
+ /* Tries to get an input stream of the Bean, reading it as a system resource
+ * if no ClassLoader is present or as an application resource if a classloader
+ * is given.
+ */
+ beanLocation =
+ (cl == null)
+ ? ClassLoader.getSystemResource(resourceName + ".ser")
+ : cl.getResource(resourceName + ".ser");
+
+ // Reads the serialized Bean from the returned URL.
+ if (beanLocation != null)
+ {
+ // Deserializes the bean instance.
+ ObjectInputStream ois =
+ (cl == null)
+ ? new ObjectInputStream(beanLocation.openStream())
+ : new ClassLoaderObjectInputStream(
+ beanLocation.openStream(),
+ cl);
+
+ bean = ois.readObject();
+
+ /* Implementation note: The result of ObjectInputStream.readObject()
+ * may have been null at this point (its a valid value to deserialize)
+ * and we explicitly want to try instantiation in such a case
+ * (this is important for compatibility).
+ */
+ }
+
+ // Instantiates the Bean using reflective instantiation if it has not been created yet.
+ if (bean == null)
+ {
+ // Makes sure that the deserialization was NOT done.
+ beanLocation = null;
+
+ Class beanClass;
+ if (cl == null)
+ {
+ beanClass = Class.forName(beanName);
+ classLocation =
+ ClassLoader.getSystemResource(resourceName + ".class");
+ }
+ else
+ {
+ beanClass = cl.loadClass(beanName);
+ classLocation = cl.getResource(resourceName + ".class");
+ }
+
+ // Instantiates and optionally registers the new bean.
+ try
+ {
+ bean = beanClass.newInstance();
+ }
+ catch(Exception e) {
+ /* Wraps all kinds of Exceptions in a ClassNotFoundException (this behavior
+ * matches with official >= 1.5, this was different for <=1.4)
+ */
+ throw new ClassNotFoundException(null, e);
+ }
+ }
+
+ /* Applet beans are treated in the following way:
+ * - all AppletS get a default AppletStub
+ * - all AppletS are initialized using the AppletInitializer instance (if it is available)
+ * - as every other Bean Applets are added to a BeanContext if one is available
+ * - each instantiated Applet is initialized using Applet.init() (this is not done for deserialized ones)
+ * - finally AppletS get activated using the AppletInitializerS activate-Method
+ *
+ * The order of operations is important for compatibility.
+ */
+ Applet applet = null;
+ if (bean instanceof Applet)
+ {
+ // Makes a second instanceof call unneccessary (instanceof is expensive).
+ applet = (Applet) bean;
+
+ /* The AppletStub's code and document base is set as follows:
+ * The code base is always the URL from where the class data originated
+ * (without the package name).
+ * If the Applet was deserialized the document base is the location of
+ * the serialized instance (usually the ".ser" file) otherwise its the URL
+ * from where the class data originated (usually the absolute directory
+ * location of the ".class" file).
+ */
+ applet.setStub(
+ new DummyAppletStub(
+ applet
+ .getClass()
+ .getProtectionDomain()
+ .getCodeSource()
+ .getLocation(),
+ (beanLocation == null) ? classLocation : beanLocation));
+
+ // Runs the Applet's initialization using an AppletInitializer.
+ if (initializer != null)
+ {
+ initializer.initialize(applet, beanContext);
+ }
+ }
+
+ // Adds the new bean to its BeanContext.
+ if (beanContext != null)
+ {
+ beanContext.add(bean);
+ }
+
+ if (applet != null)
+ {
+
+ // Initializes an instantiated (not deserialized) Applet using its own method.
+ if (beanLocation == null)
+ {
+ applet.init();
+ }
+
+ // Runs the Applet's activation using an AppletInitializer.
+ if (initializer != null)
+ {
+ initializer.activate(applet);
+ }
+ }
+
+ return bean;
+ }
+
+ /**
+ * Returns the Bean as a different class type.
+ * This should be used instead of casting to get a new
+ * type view of a Bean, because in the future there may
+ * be new types of Bean, even Beans spanning multiple
+ * Objects.
+ *
+ * @param bean the Bean to cast.
+ * @param newClass the Class to cast it to.
+ *
+ * @return the Bean as a new view, or if the operation
+ * could not be performed, the Bean itself.
+ */
+ public static Object getInstanceOf(Object bean, Class<?> newClass)
+ {
+ return bean;
+ }
+
+ /**
+ * Determines whether the Bean can be cast to a different
+ * class type.
+ * This should be used instead of instanceof to determine
+ * a Bean's castability, because in the future there may
+ * be new types of Bean, even Beans spanning multiple
+ * Objects.
+ *
+ * @param bean the Bean to cast.
+ * @param newBeanClass the Class to cast it to.
+ *
+ * @return whether the Bean can be cast to the class type
+ * in question.
+ */
+ public static boolean isInstanceOf(Object bean, Class<?> newBeanClass)
+ {
+ return newBeanClass.isInstance(bean);
+ }
+
+ /**
+ * Returns whether the GUI is available to use.
+ * <p>Defaults to true.</p>
+ *
+ * @return whether the GUI is available to use.
+ */
+ public static boolean isGuiAvailable()
+ {
+ return guiAvailable;
+ }
+
+ /**
+ * Returns whether it is design time. Design time means
+ * we are in a RAD tool.
+ * <p>Defaults to false.</p>
+ *
+ * @return whether it is design time.
+ */
+ public static boolean isDesignTime()
+ {
+ return designTime;
+ }
+
+ /**
+ * Sets whether the GUI is available to use.
+ *
+ * @param guiAvailable whether the GUI is available to use.
+ */
+ public static void setGuiAvailable(boolean guiAvailable)
+ throws SecurityException
+ {
+ Beans.guiAvailable = guiAvailable;
+ }
+
+ /**
+ * Sets whether it is design time. Design time means we
+ * are in a RAD tool.
+ *
+ * @param designTime whether it is design time.
+ */
+ public static void setDesignTime(boolean designTime)
+ throws SecurityException
+ {
+ Beans.designTime = designTime;
+ }
+
+}
diff --git a/libjava/classpath/java/beans/ConstructorProperties.java b/libjava/classpath/java/beans/ConstructorProperties.java
new file mode 100644
index 000000000..4c82c0033
--- /dev/null
+++ b/libjava/classpath/java/beans/ConstructorProperties.java
@@ -0,0 +1,72 @@
+/* ConstructorProperties.java - Associate constructor params with props
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+
+/**
+ * An annotation used to associate the parameters of a
+ * constructor with the accessor methods that later provide
+ * access to these values. For example, the parameters of
+ * the constructor <code>Person(String name, int age)</code>
+ * may be linked to the bean's two accessors, <code>getName()</code>
+ * and <code>getAge()</code> using
+ * <code>@ConstructorProperties({"name","age"})</code>.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+@Documented @Retention(RUNTIME) @Target(CONSTRUCTOR)
+public @interface ConstructorProperties
+{
+
+ /**
+ * Contains the name of the accessor methods associated
+ * with each constructor parameter.
+ *
+ * @return the accessor method names corresponding to the
+ * constructor parameters.
+ */
+ String[] value();
+
+}
diff --git a/libjava/classpath/java/beans/Customizer.java b/libjava/classpath/java/beans/Customizer.java
new file mode 100644
index 000000000..bb6b4e2dd
--- /dev/null
+++ b/libjava/classpath/java/beans/Customizer.java
@@ -0,0 +1,86 @@
+/* java.beans.Customizer
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ ** You may explicitly provide a Customizer for your Bean
+ ** class, which allows you complete control of the editing
+ ** of the Bean.<P>
+ **
+ ** A Customizer is meant to be embedded in an RAD tool,
+ ** and thus must be a descendant of <CODE>java.awt.Component</CODE>.<P>
+ **
+ ** It must also have a constructor with no arguments. This
+ ** is the constructor that will be called by the RAD tool to
+ ** instantiate the Customizer.<P>
+ **
+ ** Over its lifetime, an instance of a Customizer will only
+ ** customize one single Bean. A new instance of the
+ ** Customizer will be instantiated to edit any other Beans.<P>
+ **
+ ** The Customizer is responsible for notifying its
+ ** PropertyChangeListeners of any changes that are made,
+ ** according to the rules of PropertyChangeListeners (i.e.
+ ** notify the clients <EM>after</EM> the property has
+ ** changed).
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 29 Jul 1998
+ ** @see java.beans.BeanDescriptor.getCustomizerClass()
+ **/
+
+public interface Customizer {
+ /** Set the object to Customize. This will always be a
+ ** Bean that had a BeanDescriptor indicating this
+ ** Customizer.
+ ** @param bean the Bean to customize.
+ **/
+ void setObject(Object bean);
+
+ /** Add a PropertyChangeListener.
+ ** @param l the PropertyChangeListener to add.
+ **/
+ void addPropertyChangeListener(PropertyChangeListener l);
+
+ /** Remove a PropertyChangeListener.
+ ** @param l the PropertyChangeListener to remove.
+ **/
+ void removePropertyChangeListener(PropertyChangeListener l);
+}
diff --git a/libjava/classpath/java/beans/DefaultPersistenceDelegate.java b/libjava/classpath/java/beans/DefaultPersistenceDelegate.java
new file mode 100644
index 000000000..3a4d86cca
--- /dev/null
+++ b/libjava/classpath/java/beans/DefaultPersistenceDelegate.java
@@ -0,0 +1,211 @@
+/* DefaultPersistenceDelegate.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.beans;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/** <p><code>DefaultPersistenceDelegate</code> is a {@link PersistenceDelegate}
+ * implementation that can be used to serialize objects which adhere to the
+ * Java Beans naming convention.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.4
+ */
+public class DefaultPersistenceDelegate extends PersistenceDelegate
+{
+
+ private String[] constructorPropertyNames;
+
+ /** Using this constructor the object to be serialized will be instantiated
+ * with the default non-argument constructor.
+ */
+ public DefaultPersistenceDelegate()
+ {
+ }
+
+ /** This constructor allows to specify which Bean properties appear
+ * in the constructor.
+ *
+ * <p>The implementation reads the mentioned properties from the Bean
+ * instance and applies it in the given order to a corresponding
+ * constructor.</p>
+ *
+ * @param constructorPropertyNames The properties the Bean's constructor
+ * should be given to.
+ */
+ public DefaultPersistenceDelegate(String[] constructorPropertyNames)
+ {
+ this.constructorPropertyNames = constructorPropertyNames;
+ }
+
+ protected boolean mutatesTo(Object oldInstance, Object newInstance)
+ {
+ try
+ {
+
+ return (constructorPropertyNames != null
+ && constructorPropertyNames.length > 0
+ && oldInstance.getClass()
+ .getDeclaredMethod("equals",
+ new Class[] { Object.class }) != null)
+ ? oldInstance.equals(newInstance)
+ : super.mutatesTo(oldInstance, newInstance);
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ return super.mutatesTo(oldInstance, newInstance);
+ }
+ }
+
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ Object[] args = null;
+
+ try
+ {
+ // If there are property names in the array, then we create
+ // a corresponding argument array and store every
+ // argument in it. To retrieve an argument object we have
+ // dig up the right property in the bean class' BeanInfo
+ // object.
+ // This is so costly in terms of execution time I better
+ // not think twice about it ...
+ if (constructorPropertyNames != null)
+ {
+ args = new Object[constructorPropertyNames.length];
+
+ // Look up the properties of oldInstance's class to find matches for
+ // the
+ // names given in the constructor.
+ PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo(
+ oldInstance.getClass()).getPropertyDescriptors();
+
+ for (int i = 0; i < constructorPropertyNames.length; i++)
+ {
+ // Scan the property descriptions for a matching name.
+ for (int j = 0; j < propertyDescs.length; j++)
+ {
+ if (propertyDescs[i].getName().equals(
+ constructorPropertyNames[i]))
+ {
+ Method readMethod = propertyDescs[i].getReadMethod();
+
+ args[i] = readMethod.invoke(oldInstance);
+ }
+ }
+ }
+ }
+
+ }
+ catch (IllegalAccessException iae)
+ {
+ out.getExceptionListener().exceptionThrown(iae);
+ }
+ catch (IllegalArgumentException iarge)
+ {
+ out.getExceptionListener().exceptionThrown(iarge);
+ }
+ catch (InvocationTargetException ite)
+ {
+ out.getExceptionListener().exceptionThrown(ite);
+ }
+ catch (IntrospectionException ie)
+ {
+ out.getExceptionListener().exceptionThrown(ie);
+ }
+
+ return new Expression(oldInstance, oldInstance.getClass(), "new", args);
+ }
+
+ protected void initialize(Class<?> type, Object oldInstance,
+ Object newInstance, Encoder out)
+ {
+ // Calling the supertype's implementation of initialize makes it
+ // possible that descendants of classes like AbstractHashMap
+ // or Hashtable are serialized correctly. This mechanism grounds on
+ // two other facts:
+ // * Each class which has not registered a special purpose
+ // PersistenceDelegate is handled by a DefaultPersistenceDelegate
+ // instance.
+ // * PersistenceDelegate.initialize() is implemented in a way that it
+ // calls the initialize method of the superclass' persistence delegate.
+ super.initialize(type, oldInstance, newInstance, out);
+
+ // Suppresses the writing of property setting statements when this delegate
+ // is not used for the exact instance type. By doing so the following code
+ // is called only once per object.
+ if (type != oldInstance.getClass())
+ return;
+
+ try
+ {
+ PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo(
+ oldInstance.getClass()).getPropertyDescriptors();
+
+ for (int i = 0; i < propertyDescs.length; i++)
+ {
+ Method readMethod = propertyDescs[i].getReadMethod();
+ Method writeMethod = propertyDescs[i].getWriteMethod();
+
+ if (readMethod != null && writeMethod != null)
+ {
+ Object oldValue = readMethod.invoke(oldInstance);
+
+ if (oldValue != null)
+ out.writeStatement(new Statement(oldInstance,
+ writeMethod.getName(),
+ new Object[] { oldValue }));
+ }
+ }
+ }
+ catch (IntrospectionException ie)
+ {
+ out.getExceptionListener().exceptionThrown(ie);
+ }
+ catch (IllegalAccessException iae)
+ {
+ out.getExceptionListener().exceptionThrown(iae);
+ }
+ catch (InvocationTargetException ite)
+ {
+ out.getExceptionListener().exceptionThrown(ite);
+ }
+ }
+}
diff --git a/libjava/classpath/java/beans/DesignMode.java b/libjava/classpath/java/beans/DesignMode.java
new file mode 100644
index 000000000..bc79361c1
--- /dev/null
+++ b/libjava/classpath/java/beans/DesignMode.java
@@ -0,0 +1,95 @@
+/* java.beans.DesignMode
+ Copyright (C) 1999, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * <code>BeanContextChild</code> implementors implement this to get information
+ * about whether they are in a design time or runtime environment.
+ * The reason this is restricted to <code>BeanContextChild</code>ren is that
+ * only things in the <code>BeanContext</code> hierarchy are given this
+ * information in the first place.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ * @see java.beans.beancontext.BeanContextChild
+ */
+public interface DesignMode
+{
+
+ /**
+ * Use this name when firing <code>PropertyChangeEvent</code>s from your Bean.
+ */
+ String PROPERTYNAME = "designTime";
+
+ /**
+ * The environment will call this method on your
+ * <code>BeanContextChild</code> when it is registered in a parent
+ * <code>BeanContext</code> or when behavior needs to switch from
+ * design time to runtime behavior (or vice versa).
+ * <P>
+ *
+ * <code>BeanContext</code>s are required to fire
+ * <code>PropertyChangeEvent</code>s when properties change.
+ * <code>designTime</code> is a property, and therefore when you
+ * implement <code>setDesignTime()</code>, you need to fire a
+ * <code>PropertyChangeEvent</code> with the old value, the new
+ * value and using <code>PROPERTYNAME</code> as the property name.
+ *
+ * @param designTime the new value of design time,
+ * <code>true</code> if it is design time,
+ * <code>false</code> if it is runtime.
+ *
+ * @fixme I'm frankly not really sure whether it's the case that
+ * the BeanContext can <em>change</em> the status of the Bean from
+ * design time to runtime. But it appears that it may be so.
+ *
+ * @see java.beans.PropertyChangeEvent
+ * @see java.beans.beancontext.BeanContext
+ * @see #PROPERTYNAME
+ */
+ void setDesignTime(boolean designTime);
+
+ /**
+ * This method should tell whether it is design time or runtime.
+ * @return <code>true</code> if design time, <code>false</code> if
+ * runtime.
+ */
+ boolean isDesignTime();
+
+}
diff --git a/libjava/classpath/java/beans/Encoder.java b/libjava/classpath/java/beans/Encoder.java
new file mode 100644
index 000000000..b3d232a31
--- /dev/null
+++ b/libjava/classpath/java/beans/Encoder.java
@@ -0,0 +1,433 @@
+/* Encoder.java
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.beans.DefaultExceptionListener;
+import gnu.java.beans.encoder.ArrayPersistenceDelegate;
+import gnu.java.beans.encoder.ClassPersistenceDelegate;
+import gnu.java.beans.encoder.CollectionPersistenceDelegate;
+import gnu.java.beans.encoder.MapPersistenceDelegate;
+import gnu.java.beans.encoder.PrimitivePersistenceDelegate;
+
+import java.util.AbstractCollection;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+
+/**
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.4
+ */
+public class Encoder
+{
+
+ /**
+ * An internal DefaultPersistenceDelegate instance that is used for every
+ * class that does not a have a special special PersistenceDelegate.
+ */
+ private static PersistenceDelegate defaultPersistenceDelegate;
+
+ private static PersistenceDelegate fakePersistenceDelegate;
+
+ /**
+ * Stores the relation Class->PersistenceDelegate.
+ */
+ private static HashMap delegates = new HashMap();
+
+ /**
+ * Stores the relation oldInstance->newInstance
+ */
+ private IdentityHashMap candidates = new IdentityHashMap();
+
+ private ExceptionListener exceptionListener;
+
+ /**
+ * A simple number that is used to restrict the access to writeExpression and
+ * writeStatement. The rule is that both methods should only be used when an
+ * object is written to the stream (= writeObject). Therefore accessCounter is
+ * incremented just before the call to writeObject and decremented afterwards.
+ * Then writeStatement and writeExpression allow execution only if
+ * accessCounter is bigger than zero.
+ */
+ private int accessCounter = 0;
+
+ public Encoder()
+ {
+ setupDefaultPersistenceDelegates();
+
+ setExceptionListener(null);
+ }
+
+ /**
+ * Sets up a bunch of {@link PersistenceDelegate} instances which are needed
+ * for the basic working of a {@link Encoder}s.
+ */
+ private static void setupDefaultPersistenceDelegates()
+ {
+ synchronized (delegates)
+ {
+ if (defaultPersistenceDelegate != null)
+ return;
+
+ delegates.put(Class.class, new ClassPersistenceDelegate());
+
+ PersistenceDelegate pd = new PrimitivePersistenceDelegate();
+ delegates.put(Boolean.class, pd);
+ delegates.put(Byte.class, pd);
+ delegates.put(Short.class, pd);
+ delegates.put(Integer.class, pd);
+ delegates.put(Long.class, pd);
+ delegates.put(Float.class, pd);
+ delegates.put(Double.class, pd);
+
+ delegates.put(Object[].class, new ArrayPersistenceDelegate());
+
+ pd = new CollectionPersistenceDelegate();
+ delegates.put(AbstractCollection.class, pd);
+
+ pd = new MapPersistenceDelegate();
+ delegates.put(java.util.AbstractMap.class, pd);
+ delegates.put(java.util.Hashtable.class, pd);
+
+ defaultPersistenceDelegate = new DefaultPersistenceDelegate();
+ delegates.put(Object.class, defaultPersistenceDelegate);
+
+ // Creates a PersistenceDelegate implementation which is
+ // returned for 'null'. In practice this instance is
+ // not used in any way and is just here to be compatible
+ // with the reference implementation which returns a
+ // similar instance when calling getPersistenceDelegate(null) .
+ fakePersistenceDelegate = new PersistenceDelegate()
+ {
+ protected Expression instantiate(Object o, Encoder e)
+ {
+ return null;
+ }
+ };
+
+ }
+ }
+
+ protected void writeObject(Object o)
+ {
+ // 'null' has no PersistenceDelegate and will not
+ // create an Expression which has to be cloned.
+ // However subclasses should be aware that writeObject
+ // may be called with a 'null' argument and should
+ // write the proper representation of it.
+ if (o == null)
+ return;
+
+ PersistenceDelegate pd = getPersistenceDelegate(o.getClass());
+
+ accessCounter++;
+ pd.writeObject(o, this);
+ accessCounter--;
+
+ }
+
+ /**
+ * Sets the {@link ExceptionListener} instance to be used for reporting
+ * recorable exceptions in the instantiation and initialization sequence. If
+ * the argument is <code>null</code> a default instance will be used that
+ * prints the thrown exception to <code>System.err</code>.
+ */
+ public void setExceptionListener(ExceptionListener listener)
+ {
+ exceptionListener = (listener != null)
+ ? listener : DefaultExceptionListener.INSTANCE;
+ }
+
+ /**
+ * Returns the currently active {@link ExceptionListener} instance.
+ */
+ public ExceptionListener getExceptionListener()
+ {
+ return exceptionListener;
+ }
+
+ public PersistenceDelegate getPersistenceDelegate(Class<?> type)
+ {
+ // This is not specified but the JDK behaves like this.
+ if (type == null)
+ return fakePersistenceDelegate;
+
+ // Treats all array classes in the same way and assigns
+ // them a shared PersistenceDelegate implementation tailored
+ // for array instantation and initialization.
+ if (type.isArray())
+ return (PersistenceDelegate) delegates.get(Object[].class);
+
+ PersistenceDelegate pd = (PersistenceDelegate) delegates.get(type);
+
+ return (pd != null) ? pd : defaultPersistenceDelegate;
+ }
+
+ /**
+ * Sets the {@link PersistenceDelegate} instance for the given class.
+ * <p>
+ * Note: Throws a <code>NullPointerException</code> if the argument is
+ * <code>null</code>.
+ * </p>
+ * <p>
+ * Note: Silently ignores PersistenceDelegates for Array types and primitive
+ * wrapper classes.
+ * </p>
+ * <p>
+ * Note: Although this method is not declared <code>static</code> changes to
+ * the {@link PersistenceDelegate}s affect <strong>all</strong>
+ * {@link Encoder} instances. <strong>In this implementation</strong> the
+ * access is thread safe.
+ * </p>
+ */
+ public void setPersistenceDelegate(Class<?> type,
+ PersistenceDelegate delegate)
+ {
+ // If the argument is null this will cause a NullPointerException
+ // which is expected behavior.
+
+ // This makes custom PDs for array, primitive types and their wrappers
+ // impossible but this is how the JDK behaves.
+ if (type.isArray() || type.isPrimitive() || type == Boolean.class
+ || type == Byte.class || type == Short.class || type == Integer.class
+ || type == Long.class || type == Float.class || type == Double.class)
+ return;
+
+ synchronized (delegates)
+ {
+ delegates.put(type, delegate);
+ }
+
+ }
+
+ public Object remove(Object oldInstance)
+ {
+ return candidates.remove(oldInstance);
+ }
+
+ /**
+ * Returns the replacement object which has been created by the encoder during
+ * the instantiation sequence or <code>null</code> if the object has not
+ * been processed yet.
+ * <p>
+ * Note: The <code>String</code> class acts as an endpoint for the
+ * inherently recursive algorithm of the {@link Encoder}. Therefore instances
+ * of <code>String</code> will always be returned by this method. In other
+ * words the assertion: <code>
+ * assert (anyEncoder.get(anyString) == anyString)
+ * </code<
+ * will always hold.</p>
+ *
+ * <p>Note: If <code>null</code> is requested, the result will
+ * always be <code>null</code>.</p>
+ */
+ public Object get(Object oldInstance)
+ {
+ // String instances are handled in a special way.
+ // No one knows why this is not officially specified
+ // because this is a rather important design decision.
+ return (oldInstance == null) ? null :
+ (oldInstance.getClass() == String.class) ?
+ oldInstance : candidates.get(oldInstance);
+ }
+
+ /**
+ * <p>
+ * Note: If you call this method not from within an object instantiation and
+ * initialization sequence it will be silently ignored.
+ * </p>
+ */
+ public void writeStatement(Statement stmt)
+ {
+ // Silently ignore out of bounds calls.
+ if (accessCounter <= 0)
+ return;
+
+ Object target = stmt.getTarget();
+
+ Object newTarget = get(target);
+ if (newTarget == null)
+ {
+ writeObject(target);
+ newTarget = get(target);
+ }
+
+ Object[] args = stmt.getArguments();
+ Object[] newArgs = new Object[args.length];
+
+ for (int i = 0; i < args.length; i++)
+ {
+ newArgs[i] = get(args[i]);
+ if (newArgs[i] == null || isImmutableType(args[i].getClass()))
+ {
+ writeObject(args[i]);
+ newArgs[i] = get(args[i]);
+ }
+ }
+
+ Statement newStmt = new Statement(newTarget, stmt.getMethodName(), newArgs);
+
+ try
+ {
+ newStmt.execute();
+ }
+ catch (Exception e)
+ {
+ exceptionListener.exceptionThrown(e);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Note: If you call this method not from within an object instantiation and
+ * initialization sequence it will be silently ignored.
+ * </p>
+ */
+ public void writeExpression(Expression expr)
+ {
+ // Silently ignore out of bounds calls.
+ if (accessCounter <= 0)
+ return;
+
+ Object target = expr.getTarget();
+ Object value = null;
+ Object newValue = null;
+
+ try
+ {
+ value = expr.getValue();
+ }
+ catch (Exception e)
+ {
+ exceptionListener.exceptionThrown(e);
+ return;
+ }
+
+
+ newValue = get(value);
+
+ if (newValue == null)
+ {
+ Object newTarget = get(target);
+ if (newTarget == null)
+ {
+ writeObject(target);
+ newTarget = get(target);
+
+ // May happen if exception was thrown.
+ if (newTarget == null)
+ {
+ return;
+ }
+ }
+
+ Object[] args = expr.getArguments();
+ Object[] newArgs = new Object[args.length];
+
+ for (int i = 0; i < args.length; i++)
+ {
+ newArgs[i] = get(args[i]);
+ if (newArgs[i] == null || isImmutableType(args[i].getClass()))
+ {
+ writeObject(args[i]);
+ newArgs[i] = get(args[i]);
+ }
+ }
+
+ Expression newExpr = new Expression(newTarget, expr.getMethodName(),
+ newArgs);
+
+ // Fakes the result of Class.forName(<primitiveType>) to make it possible
+ // to hand such a type to the encoding process.
+ if (value instanceof Class && ((Class) value).isPrimitive())
+ newExpr.setValue(value);
+
+ // Instantiates the new object.
+ try
+ {
+ newValue = newExpr.getValue();
+
+ candidates.put(value, newValue);
+ }
+ catch (Exception e)
+ {
+ exceptionListener.exceptionThrown(e);
+
+ return;
+ }
+
+ writeObject(value);
+
+ }
+ else if(value.getClass() == String.class || value.getClass() == Class.class)
+ {
+ writeObject(value);
+ }
+
+ }
+
+ /** Returns whether the given class is an immutable
+ * type which has to be handled differently when serializing it.
+ *
+ * <p>Immutable objects always have to be instantiated instead of
+ * modifying an existing instance.</p>
+ *
+ * @param type The class to test.
+ * @return Whether the first argument is an immutable type.
+ */
+ boolean isImmutableType(Class type)
+ {
+ return type == String.class || type == Class.class
+ || type == Integer.class || type == Boolean.class
+ || type == Byte.class || type == Short.class
+ || type == Long.class || type == Float.class
+ || type == Double.class;
+ }
+
+ /** Sets the stream candidate for a given object.
+ *
+ * @param oldObject The object given to the encoder.
+ * @param newObject The object the encoder generated.
+ */
+ void putCandidate(Object oldObject, Object newObject)
+ {
+ candidates.put(oldObject, newObject);
+ }
+
+}
diff --git a/libjava/classpath/java/beans/EventHandler.java b/libjava/classpath/java/beans/EventHandler.java
new file mode 100644
index 000000000..967ba8294
--- /dev/null
+++ b/libjava/classpath/java/beans/EventHandler.java
@@ -0,0 +1,604 @@
+/* java.beans.EventHandler
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * <p>EventHandler forms a bridge between dynamically created listeners and
+ * arbitrary properties and methods.</p>
+ *
+ * <p>You can use this class to easily create listener implementations for
+ * some basic interactions between an event source and its target. Using
+ * the three static methods named <code>create</code> you can create
+ * these listener implementations.</p>
+ *
+ * <p>See the documentation of each method for usage examples.</p>
+ *
+ * @author Jerry Quinn (jlquinn@optonline.net)
+ * @author Robert Schuster (thebohemian@gmx.net)
+ * @since 1.4
+ */
+public class EventHandler implements InvocationHandler
+{
+ // The name of the method that will be implemented. If null, any method.
+ private String listenerMethod;
+
+ // The object to call action on.
+ private Object target;
+
+ // The name of the method or property setter in target.
+ private String action;
+
+ // The property to extract from an event passed to listenerMethod.
+ private String property;
+
+ // The target objects Class.
+ private Class targetClass;
+
+ // String class doesn't already have a capitalize routine.
+ private String capitalize(String s)
+ {
+ return s.substring(0, 1).toUpperCase() + s.substring(1);
+ }
+
+ /**
+ * Creates a new <code>EventHandler</code> instance.
+ *
+ * <p>Typical creation is done with the create method, not by knewing an
+ * EventHandler.</p>
+ *
+ * <p>This constructs an EventHandler that will connect the method
+ * listenerMethodName to target.action, extracting eventPropertyName from
+ * the first argument of listenerMethodName. and sending it to action.</p>
+ *
+ * <p>Throws a <code>NullPointerException</code> if the <code>target</code>
+ * argument is <code>null</code>.
+ *
+ * @param target Object that will perform the action.
+ * @param action A property or method of the target.
+ * @param eventPropertyName A readable property of the inbound event.
+ * @param listenerMethodName The listener method name triggering the action.
+ */
+ public EventHandler(Object target, String action, String eventPropertyName,
+ String listenerMethodName)
+ {
+ this.target = target;
+
+ // Retrieving the class is done for two reasons:
+ // 1) The class object is needed very frequently in the invoke() method.
+ // 2) The constructor should throw a NullPointerException if target is null.
+ targetClass = target.getClass();
+
+ this.action = action; // Turn this into a method or do we wait till
+ // runtime
+ property = eventPropertyName;
+ listenerMethod = listenerMethodName;
+ }
+
+ /**
+ * Returns the event property name.
+ */
+ public String getEventPropertyName()
+ {
+ return property;
+ }
+
+ /**
+ * Returns the listener's method name.
+ */
+ public String getListenerMethodName()
+ {
+ return listenerMethod;
+ }
+
+ /**
+ * Returns the target object.
+ */
+ public Object getTarget()
+ {
+ return target;
+ }
+
+ /**
+ * Returns the action method name.
+ */
+ public String getAction()
+ {
+ return action;
+ }
+
+ // Fetch a qualified property like a.b.c from object o. The properties can
+ // be boolean isProp or object getProp properties.
+ //
+ // Returns a length 2 array with the first entry containing the value
+ // extracted from the property, and the second entry contains the class of
+ // the method return type.
+ //
+ // We play this game because if the method returns a native type, the return
+ // value will be a wrapper. If we then take the type of the wrapper and use
+ // it to locate the action method that takes the native type, it won't match.
+ private Object[] getProperty(Object o, String prop)
+ {
+ // Isolate the first property name from a.b.c.
+ int pos;
+ String rest = null;
+ if ((pos = prop.indexOf('.')) != -1)
+ {
+ rest = prop.substring(pos + 1);
+ prop = prop.substring(0, pos);
+ }
+
+ // Find a method named getProp. It could be isProp instead.
+ Method getter;
+ try
+ {
+ // Look for boolean property getter isProperty
+ getter = o.getClass().getMethod("is" + capitalize(prop));
+ }
+ catch (NoSuchMethodException nsme1)
+ {
+ try {
+ // Look for regular property getter getProperty
+ getter = o.getClass().getMethod("get" + capitalize(prop));
+ } catch(NoSuchMethodException nsme2) {
+ try {
+ // Finally look for a method of the name prop
+ getter = o.getClass().getMethod(prop);
+ } catch(NoSuchMethodException nsme3) {
+ // Ok, give up with an intelligent hint for the user.
+ throw new RuntimeException("Method not called: Could not find a property or method '" + prop
+ + "' in " + o.getClass() + " while following the property argument '" + property + "'.");
+ }
+ }
+ }
+ try {
+ Object val = getter.invoke(o);
+
+ if (rest != null)
+ return getProperty(val, rest);
+
+ return new Object[] {val, getter.getReturnType()};
+ } catch(InvocationTargetException ite) {
+ throw new RuntimeException("Method not called: Property or method '" + prop + "' has thrown an exception.", ite);
+ } catch(IllegalAccessException iae) {
+ // This cannot happen because we looked up method with Class.getMethod()
+ // which returns public methods only.
+ throw (InternalError) new InternalError("Non-public method was invoked.").initCause(iae);
+ }
+ }
+
+ /**
+ * Invokes the <code>EventHandler</code>.
+ *
+ * <p>This method is normally called by the listener's proxy implementation.</p>
+ *
+ * @param proxy The listener interface that is implemented using
+ * the proxy mechanism.
+ * @param method The method that was called on the proxy instance.
+ * @param arguments The arguments which where given to the method.
+ * @throws Throwable <code>NoSuchMethodException</code> is thrown when the EventHandler's
+ * action method or property cannot be found.
+ */
+ public Object invoke(Object proxy, Method method, Object[] arguments)
+ {
+ try {
+ // The method instance of the target object. We have to find out which
+ // one we have to invoke.
+ Method actionMethod = null;
+
+ // Listener methods that weren't specified are ignored. If listenerMethod
+ // is null, then all listener methods are processed.
+ if (listenerMethod != null && !method.getName().equals(listenerMethod))
+ return null;
+
+ // If a property is defined we definitely need a valid object at
+ // arguments[0] that can be used to retrieve a value to which the
+ // property of the target gets set.
+ if(property != null) {
+ // Extracts the argument. We will let it fail with a NullPointerException
+ // the caller used a listener method that has no arguments.
+ Object event = arguments[0];
+
+ // Obtains the property XXX propertyType keeps showing up null - why?
+ // because the object inside getProperty changes, but the ref variable
+ // can't change this way, dolt! need a better way to get both values out
+ // - need method and object to do the invoke and get return type
+ Object v[] = getProperty(event, property);
+ Object[] args = new Object[] { v[0] };
+
+ // Changes the class array that controls which method signature we are going
+ // to look up in the target object.
+ Class[] argTypes = new Class[] { initClass((Class) v[1]) };
+
+ // Tries to find a setter method to which we can apply the
+ while(argTypes[0] != null) {
+ try
+ {
+ // Look for a property setter for action.
+ actionMethod = targetClass.getMethod("set" + capitalize(action), argTypes);
+
+ return actionMethod.invoke(target, args);
+ }
+ catch (NoSuchMethodException e)
+ {
+ // If action as property didn't work, try as method later.
+ }
+
+ argTypes[0] = nextClass(argTypes[0]);
+ }
+
+ // We could not find a suitable setter method. Now we try again interpreting
+ // action as the method name itself.
+ // Since we probably have changed the block local argTypes array
+ // we need to rebuild it.
+ argTypes = new Class[] { initClass((Class) v[1]) };
+
+ // Tries to find a setter method to which we can apply the
+ while(argTypes[0] != null) {
+ try
+ {
+ actionMethod = targetClass.getMethod(action, argTypes);
+
+ return actionMethod.invoke(target, args);
+ }
+ catch (NoSuchMethodException e)
+ {
+ }
+
+ argTypes[0] = nextClass(argTypes[0]);
+ }
+
+ throw new RuntimeException("Method not called: Could not find a public method named '"
+ + action + "' in target " + targetClass + " which takes a '"
+ + v[1] + "' argument or a property of this type.");
+ }
+
+ // If property was null we will search for a no-argument method here.
+ // Note: The ordering of method lookups is important because we want to prefer no-argument
+ // calls like the JDK does. This means if we have actionMethod() and actionMethod(Event) we will
+ // call the first *EVEN* if we have a valid argument for the second method. This is behavior compliant
+ // to the JDK.
+ // If actionMethod() is not available but there is a actionMethod(Event) we take this. That makes us
+ // more specification compliant than the JDK itself because this one will fail in such a case.
+ try
+ {
+ actionMethod = targetClass.getMethod(action);
+ }
+ catch(NoSuchMethodException nsme)
+ {
+ // Note: If we want to be really strict the specification says that a no-argument method should
+ // accept an EventObject (or subclass I guess). However since the official implementation is broken
+ // anyways, it's more flexible without the EventObject restriction and we are compatible on everything
+ // else this can stay this way.
+ if(arguments != null && arguments.length >= 1/* && arguments[0] instanceof EventObject*/) {
+ Class[] targetArgTypes = new Class[] { initClass(arguments[0].getClass()) };
+
+ while(targetArgTypes[0] != null) {
+ try
+ {
+ // If no property exists we expect the first element of the arguments to be
+ // an EventObject which is then applied to the target method.
+
+ actionMethod = targetClass.getMethod(action, targetArgTypes);
+
+ return actionMethod.invoke(target, new Object[] { arguments[0] });
+ }
+ catch(NoSuchMethodException nsme2)
+ {
+
+ }
+
+ targetArgTypes[0] = nextClass(targetArgTypes[0]);
+ }
+
+ }
+ }
+
+ // If we do not have a Method instance at this point this means that all our tries
+ // failed. The JDK throws an ArrayIndexOutOfBoundsException in this case.
+ if(actionMethod == null)
+ throw new ArrayIndexOutOfBoundsException(0);
+
+ // Invoke target.action(property)
+ return actionMethod.invoke(target);
+ } catch(InvocationTargetException ite) {
+ throw new RuntimeException(ite.getCause());
+ } catch(IllegalAccessException iae) {
+ // Cannot happen because we always use getMethod() which returns public
+ // methods only. Otherwise there is something seriously broken in
+ // GNU Classpath.
+ throw (InternalError) new InternalError("Non-public method was invoked.").initCause(iae);
+ }
+ }
+
+ /**
+ * <p>Returns the primitive type for every wrapper class or the
+ * class itself if it is no wrapper class.</p>
+ *
+ * <p>This is needed because to be able to find both kinds of methods:
+ * One that takes a wrapper class as the first argument and one that
+ * accepts a primitive instead.</p>
+ */
+ private Class initClass(Class klass) {
+ if(klass == Boolean.class) {
+ return Boolean.TYPE;
+ } else if(klass == Byte.class) {
+ return Byte.TYPE;
+ } else if(klass == Short.class) {
+ return Short.TYPE;
+ } else if(klass == Integer.class) {
+ return Integer.TYPE;
+ } else if(klass == Long.class) {
+ return Long.TYPE;
+ } else if(klass == Float.class) {
+ return Float.TYPE;
+ } else if(klass == Double.class) {
+ return Double.TYPE;
+ } else {
+ return klass;
+ }
+ }
+
+ /**
+ *
+ *
+ * @param klass
+ * @return
+ */
+ private Class nextClass(Class klass) {
+ if(klass == Boolean.TYPE) {
+ return Boolean.class;
+ } else if(klass == Byte.TYPE) {
+ return Byte.class;
+ } else if(klass == Short.TYPE) {
+ return Short.class;
+ } else if(klass == Integer.TYPE) {
+ return Integer.class;
+ } else if(klass == Long.TYPE) {
+ return Long.class;
+ } else if(klass == Float.TYPE) {
+ return Float.class;
+ } else if(klass == Double.TYPE) {
+ return Double.class;
+ } else {
+ return klass.getSuperclass();
+ }
+ }
+
+ /**
+ * <p>Constructs an implementation of <code>listenerInterface</code>
+ * to dispatch events.</p>
+ *
+ * <p>You can use such an implementation to simply call a public
+ * no-argument method of an arbitrary target object or to forward
+ * the first argument of the listener method to the target method.</p>
+ *
+ * <p>Call this method like:</p>
+ * <code>
+ * button.addActionListener((ActionListener)
+ * EventHandler.create(ActionListener.class, target, "dispose"));
+ * </code>
+ *
+ * <p>to achieve the following behavior:</p>
+ * <code>
+ * button.addActionListener(new ActionListener() {
+ * public void actionPerformed(ActionEvent ae) {
+ * target.dispose();
+ * }
+ * });
+ * </code>
+ *
+ * <p>That means if you need a listener implementation that simply calls a
+ * a no-argument method on a given instance for <strong>each</strong>
+ * method of the listener interface.</p>
+ *
+ * <p>Note: The <code>action</code> is interpreted as a method name. If your target object
+ * has no no-argument method of the given name the EventHandler tries to find
+ * a method with the same name but which can accept the first argument of the
+ * listener method. Usually this will be an event object but any other object
+ * will be forwarded, too. Keep in mind that using a property name instead of a
+ * real method here is wrong and will throw an <code>ArrayIndexOutOfBoundsException</code>
+ * whenever one of the listener methods is called.<p/>
+ *
+ * <p>The <code>EventHandler</code> will automatically convert primitives
+ * to their wrapper class and vice versa. Furthermore it will call
+ * a target method if it accepts a superclass of the type of the
+ * first argument of the listener method.</p>
+ *
+ * <p>In case that the method of the target object throws an exception
+ * it will be wrapped in a <code>RuntimeException</code> and thrown out
+ * of the listener method.</p>
+ *
+ * <p>In case that the method of the target object cannot be found an
+ * <code>ArrayIndexOutOfBoundsException</code> will be thrown when the
+ * listener method is invoked.</p>
+ *
+ * <p>A call to this method is equivalent to:
+ * <code>create(listenerInterface, target, action, null, null)</code></p>
+ *
+ * @param listenerInterface Listener interface to implement.
+ * @param target Object to invoke action on.
+ * @param action Target property or method to invoke.
+ * @return A constructed proxy object.
+ */
+ public static <T> T create(Class<T> listenerInterface, Object target,
+ String action)
+ {
+ return create(listenerInterface, target, action, null, null);
+ }
+
+ /**
+ * <p>Constructs an implementation of <code>listenerInterface</code>
+ * to dispatch events.</p>
+ *
+ * <p>Use this method if you want to create an implementation that retrieves
+ * a property value from the <b>first</b> argument of the listener method
+ * and applies it to the target's property or method. This first argument
+ * of the listener is usually an event object but any other object is
+ * valid, too.</p>
+ *
+ * <p>You can set the value of <code>eventPropertyName</code> to "prop"
+ * to denote the retrieval of a property named "prop" from the event
+ * object. In case that no such property exists the <code>EventHandler</code>
+ * will try to find a method with that name.</p>
+ *
+ * <p>If you set <code>eventPropertyName</code> to a value like this "a.b.c"
+ * <code>EventHandler</code> will recursively evaluate the properties "a", "b"
+ * and "c". Again if no property can be found the <code>EventHandler</code>
+ * tries a method name instead. This allows mixing the names, too: "a.toString"
+ * will retrieve the property "a" from the event object and will then call
+ * the method "toString" on it.</p>
+ *
+ * <p>An exception thrown in any of these methods will provoke a
+ * <code>RuntimeException</code> to be thrown which contains an
+ * <code>InvocationTargetException</code> containing the triggering exception.</p>
+ *
+ * <p>If you set <code>eventPropertyName</code> to a non-null value the
+ * <code>action</code> parameter will be interpreted as a property name
+ * or a method name of the target object.</p>
+ *
+ * <p>Any object retrieved from the event object and applied to the
+ * target will converted from primitives to their wrapper class or
+ * vice versa or applied to a method that accepts a superclass
+ * of the object.</p>
+ *
+ * <p>Examples:</p>
+ * <p>The following code:</p><code>
+ * button.addActionListener(
+ * new ActionListener() {
+ * public void actionPerformed(ActionEvent ae) {
+ * Object o = ae.getSource().getClass().getName();
+ * textField.setText((String) o);
+ * }
+ * });
+ * </code>
+ *
+ * <p>Can be expressed using the <code>EventHandler</code> like this:</p>
+ * <p>
+ * <code>button.addActionListener((ActionListener)
+ * EventHandler.create(ActionListener.class, textField, "text", "source.class.name");
+ * <code>
+ * </p>
+ *
+ * <p>As said above you can specify the target as a method, too:</p>
+ * <p>
+ * <code>button.addActionListener((ActionListener)
+ * EventHandler.create(ActionListener.class, textField, "setText", "source.class.name");
+ * <code>
+ * </p>
+ *
+ * <p>Furthermore you can use method names in the property:</p>
+ * <p>
+ * <code>button.addActionListener((ActionListener)
+ * EventHandler.create(ActionListener.class, textField, "setText", "getSource.getClass.getName");
+ * <code>
+ * </p>
+ *
+ * <p>Finally you can mix names:</p>
+ * <p>
+ * <code>button.addActionListener((ActionListener)
+ * EventHandler.create(ActionListener.class, textField, "setText", "source.getClass.name");
+ * <code>
+ * </p>
+ *
+ * <p>A call to this method is equivalent to:
+ * <code>create(listenerInterface, target, action, null, null)</code>
+ * </p>
+ *
+ * @param listenerInterface Listener interface to implement.
+ * @param target Object to invoke action on.
+ * @param action Target property or method to invoke.
+ * @param eventPropertyName Name of property to extract from event.
+ * @return A constructed proxy object.
+ */
+ public static <T> T create(Class<T> listenerInterface, Object target,
+ String action, String eventPropertyName)
+ {
+ return create(listenerInterface, target, action, eventPropertyName, null);
+ }
+
+ /**
+ * <p>Constructs an implementation of <code>listenerInterface</code>
+ * to dispatch events.</p>
+ *
+ * <p>Besides the functionality described for {@link create(Class, Object, String)}
+ * and {@link create(Class, Object, String, String)} this method allows you
+ * to filter the listener method that should have an effect. Look at these
+ * method's documentation for more information about the <code>EventHandler</code>'s
+ * usage.</p>
+ *
+ * <p>If you want to call <code>dispose</code> on a <code>JFrame</code> instance
+ * when the <code>WindowListener.windowClosing()</code> method was invoked use
+ * the following code:</p>
+ * <p>
+ * <code>
+ * EventHandler.create(WindowListener.class, jframeInstance, "dispose", null, "windowClosing");
+ * </code>
+ * </p>
+ *
+ * <p>A <code>NullPointerException</code> is thrown if the <code>listenerInterface</code>
+ * or <code>target</code> argument are <code>null</code>.
+ *
+ * @param listenerInterface Listener interface to implement.
+ * @param target Object to invoke action on.
+ * @param action Target method name to invoke.
+ * @param eventPropertyName Name of property to extract from event.
+ * @param listenerMethodName Listener method to implement.
+ * @return A constructed proxy object.
+ */
+ public static <T> T create(Class<T> listenerInterface, Object target,
+ String action, String eventPropertyName,
+ String listenerMethodName)
+ {
+ // Create EventHandler instance
+ EventHandler eh = new EventHandler(target, action, eventPropertyName,
+ listenerMethodName);
+
+ // Create proxy object passing in the event handler
+ Object proxy = Proxy.newProxyInstance(listenerInterface.getClassLoader(),
+ new Class<?>[] {listenerInterface},
+ eh);
+
+ return (T) proxy;
+ }
+}
diff --git a/libjava/classpath/java/beans/EventSetDescriptor.java b/libjava/classpath/java/beans/EventSetDescriptor.java
new file mode 100644
index 000000000..3f537c743
--- /dev/null
+++ b/libjava/classpath/java/beans/EventSetDescriptor.java
@@ -0,0 +1,763 @@
+/* java.beans.EventSetDescriptor
+ Copyright (C) 1998, 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.lang.ClassHelper;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Vector;
+
+/**
+ * EventSetDescriptor describes the hookup between an event source class and
+ * an event listener class.
+ *
+ * <p>EventSets have several attributes: the listener class,
+ * the events that can be fired to the listener (methods in the listener
+ * class), and an add and remove listener method from the event firer's
+ * class.
+ * </p>
+ *
+ * <p>
+ * The methods have these constraints on them:
+ * <ul>
+ * <li>event firing methods: must have <code>void</code> return value. Any
+ * parameters and exceptions are allowed. May be public, protected or
+ * package-protected. (Don't ask me why that is, I'm just following the spec.
+ * The only place it is even mentioned is in the Java Beans white paper, and
+ * there it is only implied.)</li>
+ *
+ * <li>add listener method: must have <code>void</code> return value. Must
+ * take exactly one argument, of the listener class's type. May fire either
+ * zero exceptions, or one exception of type
+ * <code>java.util.TooManyListenersException</code>.
+ * Must be public.</li>
+ *
+ * <li>remove listener method: must have <code>void</code> return value. Must
+ * take exactly one argument, of the listener class's type. May not fire any
+ * exceptions. Must be public.</li>
+ * </ul>
+ *
+ * <p>
+ * A final constraint is that event listener classes must extend from
+ * EventListener.
+ * </p>
+ *
+ * <p>
+ * There are also various design patterns associated with some of the methods
+ * of construction. Those are explained in more detail in the appropriate
+ * constructors.
+ * </p>
+ *
+ * <p>
+ * <strong>Documentation Convention:</strong> for proper Internalization of
+ * Beans inside an RAD tool, sometimes there are two names for a property or
+ * method: a programmatic, or locale-independent name, which can be used
+ * anywhere, and a localized, display name, for ease of use. In the
+ * documentation I will specify different String values as either
+ * <em>programmatic</em> or <em>localized</em> to make this distinction clear.
+ *
+ * @author John Keiser
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.1
+ */
+
+public class EventSetDescriptor extends FeatureDescriptor
+{
+ private Method addListenerMethod;
+
+ private Method removeListenerMethod;
+
+ private Class listenerType;
+
+ private MethodDescriptor[] listenerMethodDescriptors;
+
+ private Method[] listenerMethods;
+
+ private Method getListenerMethod;
+
+ private boolean unicast;
+
+ private boolean inDefaultEventSet = true;
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code<.
+ *
+ * <p>
+ * This version of the constructor enforces the rules imposed on the methods
+ * described at the top of this class, as well as searching for:
+ * </p>
+ *
+ * <ol>
+ * <li>
+ * The event-firing method must be non-private with signature <code>void
+ * &lt;listenerMethodName&gt;(&lt;eventSetName&gt;Event)</code> (where
+ * <code>&lt;eventSetName&gt;</code> has its first character capitalized
+ * by the constructor and the Event is a descendant of
+ * {@link java.util.EventObject}) in class <code>listenerType</code>
+ * (any exceptions may be thrown). <b>Implementation note:</b> Note that
+ * there could conceivably be multiple methods with this type of signature
+ * (example: <code>java.util.MouseEvent</code> vs.
+ * <code>my.very.own.MouseEvent</code>). In this implementation, all
+ * methods fitting the description will be put into the
+ * <code>EventSetDescriptor</code>, even though the spec says only one
+ * should be chosen (they probably weren't thinking as pathologically as I
+ * was). I don't like arbitrarily choosing things. If your class has only one
+ * such signature, as most do, you'll have no problems.</li>
+ *
+ * <li>The add and remove methods must be public and named <code>void
+ * add&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</code> and
+ * <code>void remove&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</code>
+ * in in class <code>eventSourceClass</code>, where
+ * <code>&lt;eventSetName&gt;</code> will have its first letter capitalized.
+ * Standard exception rules (see class description) apply.</li>
+ * </ol>
+ *
+ * @param eventSourceClass
+ * the class containing the add/remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu). This will
+ * be used to generate the name of the event object as well as the
+ * names of the add and remove methods.
+ * @param listenerType
+ * the class containing the event firing method.
+ * @param listenerMethodName
+ * the name of the event firing method.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener, or if methods are not
+ * found or are invalid.
+ */
+ public EventSetDescriptor(Class<?> eventSourceClass, String eventSetName,
+ Class<?> listenerType, String listenerMethodName)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ String[] names = new String[1];
+ names[0] = listenerMethodName;
+
+ try
+ {
+ eventSetName = Character.toUpperCase(eventSetName.charAt(0))
+ + eventSetName.substring(1);
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ eventSetName = "";
+ }
+
+ findMethods(eventSourceClass, listenerType, names,
+ "add" + eventSetName + "Listener",
+ "remove" + eventSetName + "Listener", eventSetName + "Event");
+ this.listenerType = listenerType;
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>This form of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ * </p>
+ *
+ * @param eventSourceClass
+ * the class containing the add and remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the event firing methods.
+ * @param listenerMethodNames
+ * the names of the even firing methods.
+ * @param addListenerMethodName
+ * the name of the add listener method.
+ * @param removeListenerMethodName
+ * the name of the remove listener method.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener or if methods are not
+ * found or are invalid.
+ */
+ public EventSetDescriptor(Class<?> eventSourceClass, String eventSetName,
+ Class<?> listenerType, String[] listenerMethodNames,
+ String addListenerMethodName,
+ String removeListenerMethodName)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ findMethods(eventSourceClass, listenerType, listenerMethodNames,
+ addListenerMethodName, removeListenerMethodName, null);
+ this.listenerType = listenerType;
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>
+ * This variant of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ * </p>
+ * <p>
+ * A valid GetListener method is public, flags no exceptions and has one
+ * argument which is of type <code>Class</code>
+ * {@link java.awt.Component#getListeners(Class)} is such a method.
+ * </p>
+ * <p>
+ * Note: The validity of the return value of the GetListener method is not
+ * checked.
+ * </p>
+ *
+ * @param eventSourceClass
+ * the class containing the add and remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the event firing methods.
+ * @param listenerMethodNames
+ * the names of the even firing methods.
+ * @param addListenerMethodName
+ * the name of the add listener method.
+ * @param removeListenerMethodName
+ * the name of the remove listener method.
+ * @param getListenerMethodName
+ * Name of a method which returns the array of listeners.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener or if methods are not
+ * found or are invalid.
+ * @since 1.4
+ */
+ public EventSetDescriptor(Class<?> eventSourceClass, String eventSetName,
+ Class<?> listenerType, String[] listenerMethodNames,
+ String addListenerMethodName,
+ String removeListenerMethodName,
+ String getListenerMethodName)
+ throws IntrospectionException
+ {
+ this(eventSourceClass, eventSetName, listenerType, listenerMethodNames,
+ addListenerMethodName, removeListenerMethodName);
+
+ Method newGetListenerMethod = null;
+
+ try
+ {
+ newGetListenerMethod
+ = eventSourceClass.getMethod(getListenerMethodName,
+ new Class[] { Class.class });
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ throw (IntrospectionException)
+ new IntrospectionException("No method named " + getListenerMethodName
+ + " in class " + listenerType
+ + " which can be used as"
+ + " getListenerMethod.").initCause(nsme);
+ }
+
+ // Note: This does not check the return value (which
+ // should be EventListener[]) but the JDK does not either.
+
+ getListenerMethod = newGetListenerMethod;
+
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor.</code>
+ *
+ * <p>
+ * This variant of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ * </p>
+ * <p>
+ * A valid GetListener method is public, flags no exceptions and has one
+ * argument which is of type <code>Class</code>
+ * {@link java.awt.Component#getListeners(Class)} is such a method.
+ * </p>
+ * <p>
+ * Note: The validity of the return value of the GetListener method is not
+ * checked.
+ * </p>
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethods
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @param getListenerMethod
+ * The method which returns an array of the listeners.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ * @since 1.4
+ */
+ public EventSetDescriptor(String eventSetName, Class<?> listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod,
+ Method getListenerMethod)
+ throws IntrospectionException
+ {
+ this(eventSetName, listenerType, listenerMethods, addListenerMethod,
+ removeListenerMethod);
+
+ // Do no checks if the getListenerMethod is null.
+ if (getListenerMethod.getParameterTypes().length != 1
+ || getListenerMethod.getParameterTypes()[0] != Class.class
+ || getListenerMethod.getExceptionTypes().length > 0
+ || !Modifier.isPublic(getListenerMethod.getModifiers()))
+ throw new IntrospectionException("GetListener method is invalid.");
+
+ // Note: This does not check the return value (which
+ // should be EventListener[]) but the JDK does not either.
+
+ this.getListenerMethod = getListenerMethod;
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>This form of constructor allows you to explicitly say which methods
+ * do what, and no reflection is done by the <code>EventSetDescriptor</code>.
+ * The methods are, however, checked to ensure that they follow the rules
+ * set forth at the top of the class.
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethods
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ */
+ public EventSetDescriptor(String eventSetName, Class<?> listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ this.listenerMethods = listenerMethods;
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.listenerType = listenerType;
+ checkMethods();
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /** Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>This form of constructor allows you to explicitly say which methods do
+ * what, and no reflection is done by the <code>EventSetDescriptor</code>.
+ * The methods are, however, checked to ensure that they follow the rules
+ * set forth at the top of the class.
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethodDescriptors
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ */
+ public EventSetDescriptor(String eventSetName, Class<?> listenerType,
+ MethodDescriptor[] listenerMethodDescriptors,
+ Method addListenerMethod,
+ Method removeListenerMethod)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ this.listenerMethodDescriptors = listenerMethodDescriptors;
+ this.listenerMethods = new Method[listenerMethodDescriptors.length];
+ for (int i = 0; i < this.listenerMethodDescriptors.length; i++)
+ {
+ this.listenerMethods[i]
+ = this.listenerMethodDescriptors[i].getMethod();
+ }
+
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.listenerType = listenerType;
+ checkMethods();
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /** Returns the class that contains the event firing methods.
+ */
+ public Class<?> getListenerType()
+ {
+ return listenerType;
+ }
+
+ /** Returns the event firing methods.
+ */
+ public Method[] getListenerMethods()
+ {
+ return listenerMethods;
+ }
+
+ /** Returns the event firing methods as {@link MethodDescriptor}.
+ */
+ public MethodDescriptor[] getListenerMethodDescriptors()
+ {
+ if (listenerMethodDescriptors == null)
+ {
+ listenerMethodDescriptors
+ = new MethodDescriptor[listenerMethods.length];
+
+ for (int i = 0; i < listenerMethods.length; i++)
+ {
+ listenerMethodDescriptors[i]
+ = new MethodDescriptor(listenerMethods[i]);
+ }
+ }
+
+ return listenerMethodDescriptors;
+ }
+
+ /** Returns the add listener method.
+ */
+ public Method getAddListenerMethod()
+ {
+ return addListenerMethod;
+ }
+
+ /* Returns the remove listener method.
+ */
+ public Method getRemoveListenerMethod()
+ {
+ return removeListenerMethod;
+ }
+
+ /**
+ * Returns the method that retrieves the listeners or <code>null</code> if
+ * it does not exist.
+ */
+ public Method getGetListenerMethod()
+ {
+ return getListenerMethod;
+ }
+
+ /** Sets whether or not multiple listeners may be added.
+ *
+ * @param unicast
+ * whether or not multiple listeners may be added.
+ */
+ public void setUnicast(boolean unicast)
+ {
+ this.unicast = unicast;
+ }
+
+ /** Returns whether or not multiple listeners may be added.
+ * (Defaults to false.)
+ */
+ public boolean isUnicast()
+ {
+ return unicast;
+ }
+
+ /** Sets whether or not this is in the default event set.
+ *
+ * @param inDefaultEventSet
+ * whether this is in the default event set.
+ */
+ public void setInDefaultEventSet(boolean inDefaultEventSet)
+ {
+ this.inDefaultEventSet = inDefaultEventSet;
+ }
+
+ /** Returns whether or not this is in the default event set.
+ * (Defaults to true.)
+ */
+ public boolean isInDefaultEventSet()
+ {
+ return inDefaultEventSet;
+ }
+
+ private void checkAddListenerUnicast() throws IntrospectionException
+ {
+ Class[] addListenerExceptions = this.addListenerMethod.getExceptionTypes();
+ if (addListenerExceptions.length > 1)
+ {
+ throw new IntrospectionException(
+ "Listener add method throws too many exceptions.");
+ }
+ else if (addListenerExceptions.length == 1
+ && !java.util.TooManyListenersException.class
+ .isAssignableFrom(addListenerExceptions[0]))
+ {
+ throw new IntrospectionException(
+ "Listener add method throws too many exceptions.");
+ }
+ }
+
+ private void checkMethods() throws IntrospectionException
+ {
+ if (!addListenerMethod.getDeclaringClass()
+ .isAssignableFrom(removeListenerMethod.getDeclaringClass())
+ && !removeListenerMethod.getDeclaringClass()
+ .isAssignableFrom(addListenerMethod.getDeclaringClass()))
+ {
+ throw new IntrospectionException(
+ "add and remove listener methods do not come from the"
+ + " same class. This is bad.");
+ }
+ if (!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
+ || addListenerMethod.getParameterTypes().length != 1
+ || !listenerType.equals(addListenerMethod.getParameterTypes()[0])
+ || !Modifier.isPublic(addListenerMethod.getModifiers()))
+ {
+ throw new IntrospectionException("Add Listener Method invalid.");
+ }
+ if (!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
+ || removeListenerMethod.getParameterTypes().length != 1
+ || !listenerType.equals(removeListenerMethod.getParameterTypes()[0])
+ || removeListenerMethod.getExceptionTypes().length > 0
+ || !Modifier.isPublic(removeListenerMethod.getModifiers()))
+ {
+ throw new IntrospectionException("Remove Listener Method invalid.");
+ }
+
+ for (int i = 0; i < listenerMethods.length; i++)
+ {
+ if (!listenerMethods[i].getReturnType().equals(java.lang.Void.TYPE)
+ || Modifier.isPrivate(listenerMethods[i].getModifiers()))
+ {
+ throw new IntrospectionException("Event Method "
+ + listenerMethods[i].getName()
+ + " non-void or private.");
+ }
+ if (!listenerMethods[i].getDeclaringClass()
+ .isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException("Event Method "
+ + listenerMethods[i].getName()
+ + " not from class "
+ + listenerType.getName());
+ }
+ }
+ }
+
+ private void findMethods(Class eventSourceClass, Class listenerType,
+ String listenerMethodNames[],
+ String addListenerMethodName,
+ String removeListenerMethodName,
+ String absurdEventClassCheckName)
+ throws IntrospectionException
+ {
+
+ /* Find add listener method and remove listener method. */
+ Class[] listenerArgList = new Class[1];
+ listenerArgList[0] = listenerType;
+ try
+ {
+ this.addListenerMethod
+ = eventSourceClass.getMethod(addListenerMethodName,
+ listenerArgList);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "SecurityException trying to access method "
+ + addListenerMethodName + ".");
+ }
+ catch (NoSuchMethodException E)
+ {
+ throw new IntrospectionException("Could not find method "
+ + addListenerMethodName + ".");
+ }
+
+ if (this.addListenerMethod == null
+ || !this.addListenerMethod.getReturnType().equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(
+ "Add listener method does not exist, is not public,"
+ + " or is not void.");
+ }
+
+ try
+ {
+ this.removeListenerMethod
+ = eventSourceClass.getMethod(removeListenerMethodName,
+ listenerArgList);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "SecurityException trying to access method "
+ + removeListenerMethodName + ".");
+ }
+ catch (NoSuchMethodException E)
+ {
+ throw new IntrospectionException("Could not find method "
+ + removeListenerMethodName + ".");
+ }
+ if (this.removeListenerMethod == null
+ || !this.removeListenerMethod.getReturnType()
+ .equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(
+ "Remove listener method does not exist, is not public,"
+ + " or is not void.");
+ }
+
+ /* Find the listener methods. */
+ Method[] methods;
+ try
+ {
+ methods = ClassHelper.getAllMethods(listenerType);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "Security: You cannot access fields in this class.");
+ }
+
+ Vector chosenMethods = new Vector();
+ boolean[] listenerMethodFound = new boolean[listenerMethodNames.length];
+ for (int i = 0; i < methods.length; i++)
+ {
+ if (Modifier.isPrivate(methods[i].getModifiers()))
+ {
+ continue;
+ }
+ Method currentMethod = methods[i];
+ Class retval = currentMethod.getReturnType();
+ if (retval.equals(java.lang.Void.TYPE))
+ {
+ for (int j = 0; j < listenerMethodNames.length; j++)
+ {
+ if (currentMethod.getName().equals(listenerMethodNames[j])
+ && (absurdEventClassCheckName == null
+ || (currentMethod.getParameterTypes().length == 1
+ && ((currentMethod.getParameterTypes()[0])
+ .getName().equals(absurdEventClassCheckName)
+ || (currentMethod.getParameterTypes()[0])
+ .getName().endsWith("." + absurdEventClassCheckName)))))
+ {
+ chosenMethods.addElement(currentMethod);
+ listenerMethodFound[j] = true;
+ }
+ }
+ }
+ }
+
+ /* Make sure we found all the methods we were looking for. */
+ for (int i = 0; i < listenerMethodFound.length; i++)
+ {
+ if (!listenerMethodFound[i])
+ {
+ throw new IntrospectionException("Could not find event method "
+ + listenerMethodNames[i]);
+ }
+ }
+
+ /* Now that we've chosen the listener methods we want, store them. */
+ this.listenerMethods = new Method[chosenMethods.size()];
+ for (int i = 0; i < chosenMethods.size(); i++)
+ {
+ this.listenerMethods[i] = (Method) chosenMethods.elementAt(i);
+ }
+ }
+
+}
diff --git a/libjava/classpath/java/beans/ExceptionListener.java b/libjava/classpath/java/beans/ExceptionListener.java
new file mode 100644
index 000000000..0eeb8a956
--- /dev/null
+++ b/libjava/classpath/java/beans/ExceptionListener.java
@@ -0,0 +1,57 @@
+/* ExceptionListener.java -- listen for recoverable internal exceptions
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * This interface allows a class to monitor internal exceptions, to try to
+ * recover from them.
+ *
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.4
+ * @status updated to 1.4
+ */
+public interface ExceptionListener
+{
+ /**
+ * Fired after an exception occurs.
+ *
+ * @param e the trapped exception
+ */
+ void exceptionThrown(Exception e);
+} // interface ExceptionListener
diff --git a/libjava/classpath/java/beans/Expression.java b/libjava/classpath/java/beans/Expression.java
new file mode 100644
index 000000000..d07c28b4a
--- /dev/null
+++ b/libjava/classpath/java/beans/Expression.java
@@ -0,0 +1,138 @@
+/* java.beans.Expression
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+/**
+ * <p>An Expression captures the execution of an object method
+ * that returns a value.</p>
+ *
+ * <p>It stores an object, the method to call, and the arguments to pass to
+ * the method.</p>
+ *
+ * <p>While this class can generally be used to describe method calls it is
+ * part of the XML serialization API.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.4
+ */
+public class Expression extends Statement
+{
+ // This is a placeholder to indicate that value hasn't been set
+ // yet;
+ private static final Object UNSET = new Object();
+
+ // The value to return. This is equal to unset until getValue is called.
+ private Object value;
+
+ /**
+ * Constructor Constructs an Expression representing the invocation of
+ * object.methodName(arg[0], arg[1], ...); However, it will never be executed.
+ * Instead, value will always be returned.
+ *
+ * @param value
+ * The value to return.
+ * @param target
+ * The object to invoke the method on.
+ * @param methodName
+ * The object method to invoke.
+ * @param arguments
+ * An array of arguments to pass to the method.
+ */
+ public Expression(Object value, Object target, String methodName,
+ Object[] arguments)
+ {
+ super(target, methodName, arguments);
+ this.value = value;
+ }
+
+ /**
+ * Constructor Constructs an Expression representing the invocation of
+ * object.methodName(arg[0], arg[1], ...);
+ *
+ * @param target
+ * The object to invoke the method on.
+ * @param methodName
+ * The object method to invoke.
+ * @param arguments
+ * An array of arguments to pass to the method.
+ */
+ public Expression(Object target, String methodName, Object[] arguments)
+ {
+ super(target, methodName, arguments);
+ this.value = UNSET;
+ }
+
+ /**
+ * Return the result of executing the method. If the cached value has not yet
+ * been set, the method is executed in the same way as Statement.execute(),
+ * except that the value is cached, and then returned. If the value has been
+ * set, it is returned without executing the method again.
+ *
+ * @return the result of executing the method.
+ * @exception Exception
+ * if an error occurs
+ */
+ public Object getValue() throws Exception
+ {
+ if (value == UNSET)
+ value = doExecute();
+ return value;
+ }
+
+ /**
+ * Set the cached value to be returned by getValue()
+ *
+ * @param value
+ * the value to cache and return.
+ */
+ public void setValue(Object value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Return a string representation of this expression.
+ */
+ public String toString()
+ {
+ String result = super.toString();
+ if (value != UNSET)
+ return value.getClass().getName() + "=" + result;
+ return result;
+ }
+}
diff --git a/libjava/classpath/java/beans/FeatureDescriptor.java b/libjava/classpath/java/beans/FeatureDescriptor.java
new file mode 100644
index 000000000..87e4a2fe7
--- /dev/null
+++ b/libjava/classpath/java/beans/FeatureDescriptor.java
@@ -0,0 +1,232 @@
+/* java.beans.FeatureDescriptor
+ Copyright (C) 1998, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * FeatureDescriptor is the common superclass for all JavaBeans Descriptor
+ * classes. JavaBeans descriptors are abstract descriptors of properties,
+ * events, methods, beans, etc.<P>
+ *
+ * <STRONG>Documentation Convention:</STRONG> for proper
+ * Internalization of Beans inside an RAD tool, sometimes there
+ * are two names for a property or method: a programmatic, or
+ * locale-independent name, which can be used anywhere, and a
+ * localized, display name, for ease of use. In the
+ * documentation I will specify different String values as
+ * either <EM>programmatic</EM> or <EM>localized</EM> to
+ * make this distinction clear.
+ *
+ * @author John Keiser
+ * @since 1.1
+ */
+
+public class FeatureDescriptor
+{
+ String name;
+ String displayName;
+ String shortDescription;
+ boolean expert;
+ boolean hidden;
+ boolean preferred;
+
+ Hashtable<String,Object> valueHash;
+
+ /**
+ * Instantiate this FeatureDescriptor with appropriate default values.
+ */
+ public FeatureDescriptor()
+ {
+ valueHash = new Hashtable<String,Object>();
+ }
+
+ /**
+ * Get the programmatic name of this feature.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Set the programmatic name of this feature.
+ *
+ * @param name the new name for this feature.
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Get the localized (display) name of this feature.
+ *
+ * @returns The localized display name of this feature or falls
+ * back to the programmatic name.
+ */
+ public String getDisplayName()
+ {
+ return (displayName == null) ? name : displayName;
+ }
+
+ /**
+ * Set the localized (display) name of this feature.
+ *
+ * @param displayName the new display name for this feature.
+ */
+ public void setDisplayName(String displayName)
+ {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Get the localized short description for this feature.
+ *
+ * @returns A short localized description of this feature or
+ * what <code>getDisplayName</code> returns in case, that no short description
+ * is available.
+ */
+ public String getShortDescription()
+ {
+ return (shortDescription == null) ? getDisplayName() : shortDescription;
+ }
+
+ /**
+ * Set the localized short description for this feature.
+ *
+ * @param shortDescription the new short description for this feature.
+ */
+ public void setShortDescription(String shortDescription)
+ {
+ this.shortDescription = shortDescription;
+ }
+
+ /**
+ * Indicates whether this feature is for expert use only.
+ *
+ * @return true if for use by experts only,
+ * or false if anyone can use it.
+ */
+ public boolean isExpert()
+ {
+ return expert;
+ }
+
+ /**
+ * Set whether this feature is for expert use only.
+ *
+ * @param expert true if for use by experts only,
+ * or false if anyone can use it.
+ */
+ public void setExpert(boolean expert)
+ {
+ this.expert = expert;
+ }
+
+ /**
+ * Indicates whether this feature is for use by tools only.
+ * If it is for use by tools only, then it should not be displayed.
+ *
+ * @return true if tools only should use it,
+ * or false if anyone can see it.
+ */
+ public boolean isHidden()
+ {
+ return hidden;
+ }
+
+ /**
+ * Set whether this feature is for use by tools only.
+ * If it is for use by tools only, then it should not be displayed.
+ *
+ * @param hidden true if tools only should use it,
+ * or false if anyone can see it.
+ */
+ public void setHidden(boolean hidden)
+ {
+ this.hidden = hidden;
+ }
+
+ public boolean isPreferred ()
+ {
+ return preferred;
+ }
+
+ public void setPreferred (boolean preferred)
+ {
+ this.preferred = preferred;
+ }
+
+ /**
+ * Get an arbitrary value set with setValue().
+ *
+ * @param name the programmatic name of the key.
+ *
+ * @return the value associated with this name,
+ * or null if there is none.
+ */
+ public Object getValue(String name)
+ {
+ return valueHash.get(name);
+ }
+
+ /**
+ * Set an arbitrary string-value pair with this feature.
+ *
+ * @param name the programmatic name of the key.
+ * @param value the value to associate with the name.
+ */
+ public void setValue(String name, Object value)
+ {
+ valueHash.put(name, value);
+ }
+
+ /**
+ * Get a list of the programmatic key names set with setValue().
+ *
+ * @return an Enumerator over all the programmatic key names associated
+ * with this feature.
+ */
+ public Enumeration<String> attributeNames()
+ {
+ return valueHash.keys();
+ }
+}
diff --git a/libjava/classpath/java/beans/IndexedPropertyChangeEvent.java b/libjava/classpath/java/beans/IndexedPropertyChangeEvent.java
new file mode 100644
index 000000000..9c46e1fa1
--- /dev/null
+++ b/libjava/classpath/java/beans/IndexedPropertyChangeEvent.java
@@ -0,0 +1,81 @@
+/* Indexed property change event
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * This is like a PropertyChangeEvent, but also carries with it the
+ * index of the property which changed.
+ * @author Tom Tromey (tromey@redhat.com)
+ * @since 1.5
+ */
+public class IndexedPropertyChangeEvent extends PropertyChangeEvent
+{
+ private static final long serialVersionUID = -320227448495806870L;
+
+ /**
+ * Index of the item that was changed.
+ */
+ private int index;
+
+ /**
+ * Create a new IndexedPropertyChangeEvent.
+ * @param source the Bean containing the property
+ * @param name the property's name
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
+ * @param index the index of the element in the property which changed
+ * @throws IllegalArgumentException if source is null
+ */
+ public IndexedPropertyChangeEvent(Object source, String name,
+ Object oldValue, Object newValue,
+ int index)
+ {
+ super(source, name, oldValue, newValue);
+ this.index = index;
+ }
+
+ /**
+ * Return the index of the changed property.
+ * @return the index
+ */
+ public int getIndex()
+ {
+ return index;
+ }
+}
diff --git a/libjava/classpath/java/beans/IndexedPropertyDescriptor.java b/libjava/classpath/java/beans/IndexedPropertyDescriptor.java
new file mode 100644
index 000000000..b7914133a
--- /dev/null
+++ b/libjava/classpath/java/beans/IndexedPropertyDescriptor.java
@@ -0,0 +1,421 @@
+/* IndexedPropertyDescriptor.java --
+ Copyright (C) 1998, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+
+/**
+ * IndexedPropertyDescriptor describes information about a JavaBean
+ * indexed property, by which we mean an array-like property that
+ * has been exposed via a pair of get and set methods and another
+ * pair that allows you to get to the property by an index.<P>
+ *
+ * An example property would have four methods like this:<P>
+ * <CODE>FooBar[] getFoo()</CODE><BR>
+ * <CODE>void setFoo(FooBar[])</CODE><BR>
+ * <CODE>FooBar getFoo(int)</CODE><BR>
+ * <CODE>void setFoo(int,FooBar)</CODE><P>
+ *
+ * The constraints put on get and set methods are:<P>
+ * <OL>
+ * <LI>There must be at least a get(int) or a set(int,...) method.
+ * Nothing else is required. <B>Spec note:</B>One nice restriction
+ * would be that if there is a get() there must be a get(int), same
+ * with set, but that is not in the spec and is fairly harmless.)</LI>
+ * <LI>A get array method must have signature
+ * <CODE>&lt;propertyType&gt;[] &lt;getMethodName&gt;()</CODE></LI>
+ * <LI>A set array method must have signature
+ * <CODE>void &lt;setMethodName&gt;(&lt;propertyType&gt;[])</CODE></LI>
+ * <LI>A get index method must have signature
+ * <CODE>&lt;propertyType&gt; &lt;getMethodName&gt;(int)</CODE></LI>
+ * <LI>A set index method must have signature
+ * <CODE>void &lt;setMethodName&gt;(int,&lt;propertyType&gt;)</CODE></LI>
+ * <LI>All these methods may throw any exception.</LI>
+ * <LI>All these methods must be public.</LI>
+ * </OL>
+ *
+ * @author John Keiser
+ * @since JDK1.1
+ */
+public class IndexedPropertyDescriptor extends PropertyDescriptor
+{
+ private Class<?> indexedPropertyType;
+ private Method setIndex;
+ private Method getIndex;
+
+ /**
+ * Create a new IndexedPropertyDescriptor by introspection.
+ * This form of constructor creates the PropertyDescriptor by
+ * looking for getter methods named <CODE>get&lt;name&gt;()</CODE>
+ * and setter methods named
+ * <CODE>set&lt;name&gt;()</CODE> in class
+ * <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
+ * first letter capitalized by the constructor.<P>
+ *
+ * <B>Implementation note:</B> If there is a get(int) method,
+ * then the return type of that method is used to find the
+ * remaining methods. If there is no get method, then the
+ * set(int) method is searched for exhaustively and that type
+ * is used to find the others.<P>
+ *
+ * <B>Spec note:</B>
+ * If there is no get(int) method and multiple set(int) methods with
+ * the same name and the correct parameters (different type of course),
+ * then an IntrospectionException is thrown. While Sun's spec
+ * does not state this, it can make Bean behavior different on
+ * different systems (since method order is not guaranteed) and as
+ * such, can be treated as a bug in the spec. I am not aware of
+ * whether Sun's implementation catches this.
+ *
+ * @param name the programmatic name of the property, usually
+ * starting with a lowercase letter (e.g. fooManChu
+ * instead of FooManChu).
+ * @param beanClass the class the get and set methods live in.
+ *
+ * @exception IntrospectionException if the methods are not found or
+ * invalid.
+ */
+ public IndexedPropertyDescriptor(String name, Class<?> beanClass)
+ throws IntrospectionException
+ {
+ super(name);
+ String capitalized;
+ try
+ {
+ capitalized = Character.toUpperCase(name.charAt(0))
+ + name.substring(1);
+ }
+ catch(StringIndexOutOfBoundsException e)
+ {
+ capitalized = "";
+ }
+ findMethods(beanClass, "get" + capitalized, "set" + capitalized,
+ "get" + capitalized, "set" + capitalized);
+ }
+
+ /**
+ * Create a new IndexedPropertyDescriptor by introspection.
+ * This form of constructor allows you to specify the
+ * names of the get and set methods to search for.<P>
+ *
+ * <B>Implementation note:</B> If there is a get(int) method,
+ * then the return type of that method is used to find the
+ * remaining methods. If there is no get method, then the
+ * set(int) method is searched for exhaustively and that type
+ * is used to find the others.<P>
+ *
+ * <B>Spec note:</B>
+ * If there is no get(int) method and multiple set(int) methods with
+ * the same name and the correct parameters (different type of course),
+ * then an IntrospectionException is thrown. While Sun's spec
+ * does not state this, it can make Bean behavior different on
+ * different systems (since method order is not guaranteed) and as
+ * such, can be treated as a bug in the spec. I am not aware of
+ * whether Sun's implementation catches this.
+ *
+ * @param name the programmatic name of the property, usually
+ * starting with a lowercase letter (e.g. fooManChu
+ * instead of FooManChu).
+ * @param beanClass the class the get and set methods live in.
+ * @param getMethodName the name of the get array method.
+ * @param setMethodName the name of the set array method.
+ * @param getIndexName the name of the get index method.
+ * @param setIndexName the name of the set index method.
+ *
+ * @exception IntrospectionException if the methods are not found or invalid.
+ */
+ public IndexedPropertyDescriptor(String name, Class<?> beanClass,
+ String getMethodName, String setMethodName,
+ String getIndexName, String setIndexName)
+ throws IntrospectionException
+ {
+ super(name);
+ findMethods(beanClass, getMethodName, setMethodName, getIndexName,
+ setIndexName);
+ }
+
+ /**
+ * Create a new PropertyDescriptor using explicit Methods.
+ * Note that the methods will be checked for conformance to standard
+ * Property method rules, as described above at the top of this class.
+ *
+ * @param name the programmatic name of the property, usually
+ * starting with a lowercase letter (e.g. fooManChu
+ * instead of FooManChu).
+ * @param getMethod the get array method.
+ * @param setMethod the set array method.
+ * @param getIndex the get index method.
+ * @param setIndex the set index method.
+ *
+ * @exception IntrospectionException if the methods are not found or invalid.
+ */
+ public IndexedPropertyDescriptor(String name, Method getMethod,
+ Method setMethod, Method getIndex,
+ Method setIndex)
+ throws IntrospectionException
+ {
+ super(name);
+ if(getMethod != null && getMethod.getParameterTypes().length > 0)
+ throw new IntrospectionException("get method has parameters");
+ if(getMethod != null && setMethod.getParameterTypes().length != 1)
+ throw new IntrospectionException("set method does not have exactly one parameter");
+ if(getMethod != null && setMethod != null)
+ {
+ if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0]))
+ {
+ throw new IntrospectionException("set and get methods do not "
+ + "share the same type");
+ }
+ if(!getMethod.getDeclaringClass().isAssignableFrom
+ (setMethod.getDeclaringClass())
+ && !setMethod.getDeclaringClass().isAssignableFrom
+ (getMethod.getDeclaringClass()))
+ {
+ throw new IntrospectionException("set and get methods are not in "
+ + "the same class.");
+ }
+ }
+
+ if (getIndex != null
+ && (getIndex.getParameterTypes().length != 1
+ || !(getIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE)))
+ {
+ throw new IntrospectionException("get index method has wrong "
+ + "parameters");
+ }
+ if (setIndex != null
+ && (setIndex.getParameterTypes().length != 2
+ || !(setIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE)))
+ {
+ throw new IntrospectionException("set index method has wrong "
+ + "parameters");
+ }
+ if (getIndex != null && setIndex != null)
+ {
+ if(!getIndex.getReturnType().equals(setIndex.getParameterTypes()[1]))
+ {
+ throw new IntrospectionException("set index methods do not share "
+ + "the same type");
+ }
+ if(!getIndex.getDeclaringClass().isAssignableFrom
+ (setIndex.getDeclaringClass())
+ && !setIndex.getDeclaringClass().isAssignableFrom
+ (getIndex.getDeclaringClass()))
+ {
+ throw new IntrospectionException("get and set index methods are "
+ + "not in the same class.");
+ }
+ }
+
+ if (getIndex != null && getMethod != null
+ && !getIndex.getDeclaringClass().isAssignableFrom
+ (getMethod.getDeclaringClass())
+ && !getMethod.getDeclaringClass().isAssignableFrom
+ (getIndex.getDeclaringClass()))
+ {
+ throw new IntrospectionException("methods are not in the same class.");
+ }
+
+ if (getIndex != null && getMethod != null
+ && !Array.newInstance(getIndex.getReturnType(),0)
+ .getClass().equals(getMethod.getReturnType()))
+ {
+ throw new IntrospectionException("array methods do not match index "
+ + "methods.");
+ }
+
+ this.getMethod = getMethod;
+ this.setMethod = setMethod;
+ this.getIndex = getIndex;
+ this.setIndex = setIndex;
+ this.indexedPropertyType = getIndex != null ? getIndex.getReturnType()
+ : setIndex.getParameterTypes()[1];
+ this.propertyType = getMethod != null ? getMethod.getReturnType()
+ : (setMethod != null ? setMethod.getParameterTypes()[0]
+ : Array.newInstance(this.indexedPropertyType,0).getClass());
+ }
+
+ public Class<?> getIndexedPropertyType()
+ {
+ return indexedPropertyType;
+ }
+
+ public Method getIndexedReadMethod()
+ {
+ return getIndex;
+ }
+
+ /**
+ * Sets the method that is used to read an indexed property.
+ *
+ * @param m the method to set
+ */
+ public void setIndexedReadMethod(Method m) throws IntrospectionException
+ {
+ getIndex = m;
+ }
+
+ public Method getIndexedWriteMethod()
+ {
+ return setIndex;
+ }
+
+ /**
+ * Sets the method that is used to write an indexed property.
+ *
+ * @param m the method to set
+ */
+ public void setIndexedWriteMethod(Method m) throws IntrospectionException
+ {
+ setIndex = m;
+ }
+
+ private void findMethods(Class beanClass, String getMethodName,
+ String setMethodName, String getIndexName,
+ String setIndexName)
+ throws IntrospectionException
+ {
+ try
+ {
+ if(getIndexName != null)
+ {
+ try
+ {
+ Class[] getArgs = new Class[1];
+ getArgs[0] = java.lang.Integer.TYPE;
+ getIndex = beanClass.getMethod(getIndexName,getArgs);
+ indexedPropertyType = getIndex.getReturnType();
+ }
+ catch(NoSuchMethodException E)
+ {
+ }
+ }
+ if(getIndex != null)
+ {
+ if(setIndexName != null)
+ {
+ try
+ {
+ Class[] setArgs = new Class[2];
+ setArgs[0] = java.lang.Integer.TYPE;
+ setArgs[1] = indexedPropertyType;
+ setIndex = beanClass.getMethod(setIndexName,setArgs);
+ if(!setIndex.getReturnType().equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(setIndexName
+ + " has non-void return type");
+ }
+ }
+ catch(NoSuchMethodException E)
+ {
+ }
+ }
+ }
+ else if(setIndexName != null)
+ {
+ Method[] m = beanClass.getMethods();
+ for(int i=0;i<m.length;i++)
+ {
+ Method current = m[i];
+ if(current.getName().equals(setIndexName)
+ && current.getParameterTypes().length == 2
+ && (current.getParameterTypes()[0])
+ .equals(java.lang.Integer.TYPE)
+ && current.getReturnType().equals(java.lang.Void.TYPE))
+ {
+ if(setIndex != null)
+ {
+ throw new IntrospectionException("Multiple, different "
+ + "set methods found that fit the bill!");
+ }
+ else
+ {
+ setIndex = current;
+ indexedPropertyType = current.getParameterTypes()[1];
+ }
+ }
+ }
+ if(setIndex == null)
+ {
+ throw new IntrospectionException("Cannot find get or set "
+ + "methods.");
+ }
+ }
+ else
+ {
+ throw new IntrospectionException("Cannot find get or set methods.");
+ }
+
+ Class arrayType = Array.newInstance(indexedPropertyType,0).getClass();
+
+ Class[] setArgs = new Class[1];
+ setArgs[0] = arrayType;
+ try
+ {
+ setMethod = beanClass.getMethod(setMethodName,setArgs);
+ if (!setMethod.getReturnType().equals(java.lang.Void.TYPE))
+ {
+ setMethod = null;
+ }
+ }
+ catch(NoSuchMethodException E)
+ {
+ }
+
+ Class[] getArgs = new Class[0];
+ try
+ {
+ getMethod = beanClass.getMethod(getMethodName,getArgs);
+ if (!getMethod.getReturnType().equals(arrayType))
+ {
+ getMethod = null;
+ }
+ }
+ catch(NoSuchMethodException E)
+ {
+ }
+ }
+ catch(SecurityException E)
+ {
+ throw new IntrospectionException("SecurityException while trying to "
+ + "find methods.");
+ }
+ }
+}
diff --git a/libjava/classpath/java/beans/IntrospectionException.java b/libjava/classpath/java/beans/IntrospectionException.java
new file mode 100644
index 000000000..7bb83dac5
--- /dev/null
+++ b/libjava/classpath/java/beans/IntrospectionException.java
@@ -0,0 +1,67 @@
+/* IntrospectionException -- thrown when an exception occurs in introspection
+ Copyright (C) 1998, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * IntrospectionException is thrown when the Introspector fails. Typical
+ * causes are the inability to map a name to its Class, or specifying a
+ * wrong type signature.
+ *
+ * @author John Keiser
+ * @see Introspector
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class IntrospectionException extends Exception
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -3728150539969542619L;
+
+ /**
+ * Instantiate this exception with the given message.
+ *
+ * @param msg the message for the exception
+ */
+ public IntrospectionException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/classpath/java/beans/Introspector.java b/libjava/classpath/java/beans/Introspector.java
new file mode 100644
index 000000000..76412e022
--- /dev/null
+++ b/libjava/classpath/java/beans/Introspector.java
@@ -0,0 +1,705 @@
+/* java.beans.Introspector
+ Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.beans.BeanInfoEmbryo;
+import gnu.java.beans.ExplicitBeanInfo;
+import gnu.java.beans.IntrospectionIncubator;
+import gnu.java.lang.ClassHelper;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * Introspector is the class that does the bulk of the
+ * design-time work in Java Beans. Every class must have
+ * a BeanInfo in order for an RAD tool to use it; but, as
+ * promised, you don't have to write the BeanInfo class
+ * yourself if you don't want to. All you have to do is
+ * call getBeanInfo() in the Introspector and it will use
+ * standard JavaBeans-defined method signatures to
+ * determine the information about your class.<P>
+ *
+ * Don't worry about it too much, though: you can provide
+ * JavaBeans with as much customized information as you
+ * want, or as little as you want, using the BeanInfo
+ * interface (see BeanInfo for details).<P>
+ *
+ * <STRONG>Order of Operations</STRONG><P>
+ *
+ * When you call getBeanInfo(class c), the Introspector
+ * first searches for BeanInfo class to see if you
+ * provided any explicit information. It searches for a
+ * class named &lt;bean class name&gt;BeanInfo in different
+ * packages, first searching the bean class's package
+ * and then moving on to search the beanInfoSearchPath.<P>
+ *
+ * If it does not find a BeanInfo class, it acts as though
+ * it had found a BeanInfo class returning null from all
+ * methods (meaning it should discover everything through
+ * Introspection). If it does, then it takes the
+ * information it finds in the BeanInfo class to be
+ * canonical (that is, the information speaks for its
+ * class as well as all superclasses).<P>
+ *
+ * When it has introspected the class, calls
+ * getBeanInfo(c.getSuperclass) and adds that information
+ * to the information it has, not adding to any information
+ * it already has that is canonical.<P>
+ *
+ * <STRONG>Introspection Design Patterns</STRONG><P>
+ *
+ * When the Introspector goes in to read the class, it
+ * follows a well-defined order in order to not leave any
+ * methods unaccounted for. Its job is to step over all
+ * of the public methods in a class and determine whether
+ * they are part of a property, an event, or a method (in
+ * that order).
+ *
+ *
+ * <STRONG>Properties:</STRONG><P>
+ *
+ * <OL>
+ * <LI>If there is a <CODE>public boolean isXXX()</CODE>
+ * method, then XXX is a read-only boolean property.
+ * <CODE>boolean getXXX()</CODE> may be supplied in
+ * addition to this method, although isXXX() is the
+ * one that will be used in this case and getXXX()
+ * will be ignored. If there is a
+ * <CODE>public void setXXX(boolean)</CODE> method,
+ * it is part of this group and makes it a read-write
+ * property.</LI>
+ * <LI>If there is a
+ * <CODE>public &lt;type&gt; getXXX(int)</CODE>
+ * method, then XXX is a read-only indexed property of
+ * type &lt;type&gt;. If there is a
+ * <CODE>public void setXXX(int,&lt;type&gt;)</CODE>
+ * method, then it is a read-write indexed property of
+ * type &lt;type&gt;. There may also be a
+ * <CODE>public &lt;type&gt;[] getXXX()</CODE> and a
+ * <CODE>public void setXXX(&lt;type&gt;)</CODE>
+ * method as well.</LI>
+ * <LI>If there is a
+ * <CODE>public void setXXX(int,&lt;type&gt;)</CODE>
+ * method, then it is a write-only indexed property of
+ * type &lt;type&gt;. There may also be a
+ * <CODE>public &lt;type&gt;[] getXXX()</CODE> and a
+ * <CODE>public void setXXX(&lt;type&gt;)</CODE>
+ * method as well.</LI>
+ * <LI>If there is a
+ * <CODE>public &lt;type&gt; getXXX()</CODE> method,
+ * then XXX is a read-only property of type
+ * &lt;type&gt;. If there is a
+ * <CODE>public void setXXX(&lt;type&gt;)</CODE>
+ * method, then it will be used for the property and
+ * the property will be considered read-write.</LI>
+ * <LI>If there is a
+ * <CODE>public void setXXX(&lt;type&gt;)</CODE>
+ * method, then as long as XXX is not already used as
+ * the name of a property, XXX is assumed to be a
+ * write-only property of type &lt;type&gt;.</LI>
+ * <LI>In all of the above cases, if the setXXX() method
+ * throws <CODE>PropertyVetoException</CODE>, then the
+ * property in question is assumed to be constrained.
+ * No properties are ever assumed to be bound
+ * (<STRONG>Spec Note:</STRONG> this is not in the
+ * spec, it just makes sense). See PropertyDescriptor
+ * for a description of bound and constrained
+ * properties.</LI>
+ * </OL>
+ *
+ * <STRONG>Events:</STRONG><P>
+ *
+ * If there is a pair of methods,
+ * <CODE>public void addXXX(&lt;type&gt;)</CODE> and
+ * <CODE>public void removeXXX(&lt;type&gt;)</CODE>, where
+ * &lt;type&gt; is a descendant of
+ * <CODE>java.util.EventListener</CODE>, then the pair of
+ * methods imply that this Bean will fire events to
+ * listeners of type &lt;type&gt;.<P>
+ *
+ * If the addXXX() method throws
+ * <CODE>java.util.TooManyListenersException</CODE>, then
+ * the event set is assumed to be <EM>unicast</EM>. See
+ * EventSetDescriptor for a discussion of unicast event
+ * sets.<P>
+ *
+ * <STRONG>Spec Note:</STRONG> the spec seems to say that
+ * the listener type's classname must be equal to the XXX
+ * part of addXXX() and removeXXX(), but that is not the
+ * case in Sun's implementation, so I am assuming it is
+ * not the case in general.<P>
+ *
+ * <STRONG>Methods:</STRONG><P>
+ *
+ * Any public methods (including those which were used
+ * for Properties or Events) are used as Methods.
+ *
+ * @author John Keiser
+ * @since JDK1.1
+ * @see java.beans.BeanInfo
+ */
+public class Introspector {
+
+ public static final int USE_ALL_BEANINFO = 1;
+ public static final int IGNORE_IMMEDIATE_BEANINFO = 2;
+ public static final int IGNORE_ALL_BEANINFO = 3;
+
+ static String[] beanInfoSearchPath = {"gnu.java.beans.info"};
+ static Hashtable<Class<?>,BeanInfo> beanInfoCache =
+ new Hashtable<Class<?>,BeanInfo>();
+
+ private Introspector() {}
+
+ /**
+ * Get the BeanInfo for class <CODE>beanClass</CODE>,
+ * first by looking for explicit information, next by
+ * using standard design patterns to determine
+ * information about the class.
+ *
+ * @param beanClass the class to get BeanInfo about.
+ * @return the BeanInfo object representing the class.
+ */
+ public static BeanInfo getBeanInfo(Class<?> beanClass)
+ throws IntrospectionException
+ {
+ BeanInfo cachedInfo;
+ synchronized(beanClass)
+ {
+ cachedInfo = beanInfoCache.get(beanClass);
+ if(cachedInfo != null)
+ {
+ return cachedInfo;
+ }
+ cachedInfo = getBeanInfo(beanClass,null);
+ beanInfoCache.put(beanClass,cachedInfo);
+ return cachedInfo;
+ }
+ }
+
+ /**
+ * Returns a {@BeanInfo} instance for the given Bean class where a flag
+ * controls the usage of explicit BeanInfo class to retrieve that
+ * information.
+ *
+ * <p>You have three options:</p>
+ * <p>With {@link #USE_ALL_BEANINFO} the result is the same as
+ * {@link #getBeanInfo(Class)}.</p>
+ *
+ * <p>Calling the method with <code>flag</code> set to
+ * {@link #IGNORE_IMMEDIATE_BEANINFO} will let it use all
+ * explicit BeanInfo classes for the beans superclasses
+ * but not for the bean class itself. Furthermore eventset,
+ * property and method information is retrieved by introspection
+ * if the explicit <code>BeanInfos</code> did not provide such data
+ * (ie. return <code>null</code> on {@link BeanInfo.getMethodDescriptors},
+ * {@link BeanInfo.getEventSetDescriptors} and
+ * {@link BeanInfo.getPropertyDescriptors}.)
+ * </p>
+ *
+ * <p>When the method is called with <code>flag</code< set to
+ * {@link #IGNORE_ALL_BEANINFO} all the bean data is retrieved
+ * by inspecting the class.</p>
+ *
+ * <p>Note: Any unknown value for <code>flag</code> is interpreted
+ * as {@link #IGNORE_ALL_BEANINFO}</p>.
+ *
+ * @param beanClass The class whose BeanInfo should be returned.
+ * @param flag Controls the usage of explicit <code>BeanInfo</code> classes.
+ * @return A BeanInfo object describing the class.
+ * @throws IntrospectionException If something goes wrong while retrieving
+ * the bean data.
+ */
+ public static BeanInfo getBeanInfo(Class<?> beanClass, int flag)
+ throws IntrospectionException
+ {
+ IntrospectionIncubator ii;
+ BeanInfoEmbryo infoEmbryo;
+
+ switch(flag)
+ {
+ case USE_ALL_BEANINFO:
+ return getBeanInfo(beanClass);
+ case IGNORE_IMMEDIATE_BEANINFO:
+ Class superclass = beanClass.getSuperclass();
+ ExplicitInfo explicit = new ExplicitInfo(superclass, null);
+
+ ii = new IntrospectionIncubator();
+ if (explicit.explicitEventSetDescriptors != null)
+ ii.setEventStopClass(superclass);
+
+ if (explicit.explicitMethodDescriptors != null)
+ ii.setMethodStopClass(superclass);
+
+ if (explicit.explicitPropertyDescriptors != null)
+ ii.setPropertyStopClass(superclass);
+
+ ii.addMethods(beanClass.getMethods());
+
+ infoEmbryo = ii.getBeanInfoEmbryo();
+ merge(infoEmbryo, explicit);
+
+ infoEmbryo.setBeanDescriptor(new BeanDescriptor(beanClass, null));
+
+ return infoEmbryo.getBeanInfo();
+ case IGNORE_ALL_BEANINFO:
+ default:
+ ii = new IntrospectionIncubator();
+ ii.addMethods(beanClass.getMethods());
+ infoEmbryo = ii.getBeanInfoEmbryo();
+ infoEmbryo.setBeanDescriptor(new BeanDescriptor(beanClass, null));
+
+ return infoEmbryo.getBeanInfo();
+ }
+ }
+
+ /**
+ * Flush all of the Introspector's internal caches.
+ *
+ * @since 1.2
+ */
+ public static void flushCaches()
+ {
+ beanInfoCache.clear();
+
+ // Clears all the intermediate ExplicitInfo instances which
+ // have been created.
+ // This makes sure we have to retrieve stuff like BeanDescriptors
+ // again. (Remember that FeatureDescriptor can be modified by the user.)
+ ExplicitInfo.flushCaches();
+ }
+
+ /**
+ * Flush the Introspector's internal cached information for a given
+ * class.
+ *
+ * @param clz the class to be flushed.
+ * @throws NullPointerException if clz is null.
+ * @since 1.2
+ */
+ public static void flushFromCaches(Class<?> clz)
+ {
+ synchronized (clz)
+ {
+ beanInfoCache.remove(clz);
+ }
+ }
+
+ /** Adds all explicity given bean info data to the introspected
+ * data.
+ *
+ * @param infoEmbryo Bean info data retrieved by introspection.
+ * @param explicit Bean info data retrieved by BeanInfo classes.
+ */
+ private static void merge(BeanInfoEmbryo infoEmbryo, ExplicitInfo explicit)
+ {
+ PropertyDescriptor[] p = explicit.explicitPropertyDescriptors;
+ if(p!=null)
+ {
+ for(int i=0;i<p.length;i++)
+ {
+ if(!infoEmbryo.hasProperty(p[i]))
+ {
+ infoEmbryo.addProperty(p[i]);
+ }
+ }
+
+ // -1 should be used to denote a missing default property but
+ // for robustness reasons any value below zero is discarded.
+ // Not doing so would let Classpath fail where the JDK succeeds.
+ if(explicit.defaultProperty > -1)
+ {
+ infoEmbryo.setDefaultPropertyName(p[explicit.defaultProperty].getName());
+ }
+ }
+ EventSetDescriptor[] e = explicit.explicitEventSetDescriptors;
+ if(e!=null)
+ {
+ for(int i=0;i<e.length;i++)
+ {
+ if(!infoEmbryo.hasEvent(e[i]))
+ {
+ infoEmbryo.addEvent(e[i]);
+ }
+ }
+
+ // -1 should be used to denote a missing default event but
+ // for robustness reasons any value below zero is discarded.
+ // Not doing so would let Classpath fail where the JDK succeeds.
+ if(explicit.defaultEvent > -1)
+ {
+ infoEmbryo.setDefaultEventName(e[explicit.defaultEvent].getName());
+ }
+ }
+ MethodDescriptor[] m = explicit.explicitMethodDescriptors;
+ if(m!=null)
+ {
+ for(int i=0;i<m.length;i++)
+ {
+ if(!infoEmbryo.hasMethod(m[i]))
+ {
+ infoEmbryo.addMethod(m[i]);
+ }
+ }
+ }
+
+ infoEmbryo.setAdditionalBeanInfo(explicit.explicitBeanInfo);
+ infoEmbryo.setIcons(explicit.im);
+
+ }
+
+ /**
+ * Get the BeanInfo for class <CODE>beanClass</CODE>,
+ * first by looking for explicit information, next by
+ * using standard design patterns to determine
+ * information about the class. It crawls up the
+ * inheritance tree until it hits <CODE>topClass</CODE>.
+ *
+ * @param beanClass the Bean class.
+ * @param stopClass the class to stop at.
+ * @return the BeanInfo object representing the class.
+ */
+ public static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass)
+ throws IntrospectionException
+ {
+ ExplicitInfo explicit = new ExplicitInfo(beanClass, stopClass);
+
+ IntrospectionIncubator ii = new IntrospectionIncubator();
+ ii.setPropertyStopClass(explicit.propertyStopClass);
+ ii.setEventStopClass(explicit.eventStopClass);
+ ii.setMethodStopClass(explicit.methodStopClass);
+ ii.addMethods(beanClass.getMethods());
+
+ BeanInfoEmbryo currentInfo = ii.getBeanInfoEmbryo();
+
+ merge(currentInfo, explicit);
+
+ // Sets the info's BeanDescriptor to the one we extracted from the
+ // explicit BeanInfo instance(s) if they contained one. Otherwise we
+ // create the BeanDescriptor from scratch.
+ // Note: We do not create a copy the retrieved BeanDescriptor which will allow
+ // the user to modify the instance while it is cached. However this is how
+ // the RI does it.
+ currentInfo.setBeanDescriptor(
+ (explicit.explicitBeanDescriptor == null ?
+ new BeanDescriptor(beanClass, null) :
+ explicit.explicitBeanDescriptor));
+ return currentInfo.getBeanInfo();
+ }
+
+ /**
+ * Get the search path for BeanInfo classes.
+ *
+ * @return the BeanInfo search path.
+ */
+ public static String[] getBeanInfoSearchPath()
+ {
+ return beanInfoSearchPath;
+ }
+
+ /**
+ * Set the search path for BeanInfo classes.
+ * @param beanInfoSearchPath the new BeanInfo search
+ * path.
+ */
+ public static void setBeanInfoSearchPath(String[] beanInfoSearchPath)
+ {
+ Introspector.beanInfoSearchPath = beanInfoSearchPath;
+ }
+
+ /**
+ * A helper method to convert a name to standard Java
+ * naming conventions: anything with two capitals as the
+ * first two letters remains the same, otherwise the
+ * first letter is decapitalized. URL = URL, I = i,
+ * MyMethod = myMethod.
+ *
+ * @param name the name to decapitalize.
+ * @return the decapitalized name.
+ */
+ public static String decapitalize(String name)
+ {
+ try
+ {
+ if(!Character.isUpperCase(name.charAt(0)))
+ {
+ return name;
+ }
+ else
+ {
+ try
+ {
+ if(Character.isUpperCase(name.charAt(1)))
+ {
+ return name;
+ }
+ else
+ {
+ char[] c = name.toCharArray();
+ c[0] = Character.toLowerCase(c[0]);
+ return new String(c);
+ }
+ }
+ catch(StringIndexOutOfBoundsException E)
+ {
+ char[] c = new char[1];
+ c[0] = Character.toLowerCase(name.charAt(0));
+ return new String(c);
+ }
+ }
+ }
+ catch(StringIndexOutOfBoundsException E)
+ {
+ return name;
+ }
+ catch(NullPointerException E)
+ {
+ return null;
+ }
+ }
+
+ static BeanInfo copyBeanInfo(BeanInfo b)
+ {
+ java.awt.Image[] icons = new java.awt.Image[4];
+ for(int i=1;i<=4;i++)
+ {
+ icons[i-1] = b.getIcon(i);
+ }
+
+ return new ExplicitBeanInfo(b.getBeanDescriptor(),
+ b.getAdditionalBeanInfo(),
+ b.getPropertyDescriptors(),
+ b.getDefaultPropertyIndex(),
+ b.getEventSetDescriptors(),
+ b.getDefaultEventIndex(),
+ b.getMethodDescriptors(),
+ icons);
+ }
+}
+
+class ExplicitInfo
+{
+ BeanDescriptor explicitBeanDescriptor;
+ BeanInfo[] explicitBeanInfo;
+
+ PropertyDescriptor[] explicitPropertyDescriptors;
+ EventSetDescriptor[] explicitEventSetDescriptors;
+ MethodDescriptor[] explicitMethodDescriptors;
+
+ int defaultProperty;
+ int defaultEvent;
+
+ java.awt.Image[] im = new java.awt.Image[4];
+
+ Class propertyStopClass;
+ Class eventStopClass;
+ Class methodStopClass;
+
+ static Hashtable explicitBeanInfos = new Hashtable();
+ static Vector emptyBeanInfos = new Vector();
+
+ ExplicitInfo(Class beanClass, Class stopClass)
+ {
+ while(beanClass != null && !beanClass.equals(stopClass))
+ {
+
+ BeanInfo explicit = findExplicitBeanInfo(beanClass);
+
+
+ if(explicit != null)
+ {
+
+ if(explicitBeanDescriptor == null)
+ {
+ explicitBeanDescriptor = explicit.getBeanDescriptor();
+ }
+
+ if(explicitBeanInfo == null)
+ {
+ explicitBeanInfo = explicit.getAdditionalBeanInfo();
+ }
+
+ if(explicitPropertyDescriptors == null)
+ {
+ if(explicit.getPropertyDescriptors() != null)
+ {
+ explicitPropertyDescriptors = explicit.getPropertyDescriptors();
+ defaultProperty = explicit.getDefaultPropertyIndex();
+ propertyStopClass = beanClass;
+ }
+ }
+
+ if(explicitEventSetDescriptors == null)
+ {
+ if(explicit.getEventSetDescriptors() != null)
+ {
+ explicitEventSetDescriptors = explicit.getEventSetDescriptors();
+ defaultEvent = explicit.getDefaultEventIndex();
+ eventStopClass = beanClass;
+ }
+ }
+
+ if(explicitMethodDescriptors == null)
+ {
+ if(explicit.getMethodDescriptors() != null)
+ {
+ explicitMethodDescriptors = explicit.getMethodDescriptors();
+ methodStopClass = beanClass;
+ }
+ }
+
+ if(im[0] == null && im[1] == null
+ && im[2] == null && im[3] == null)
+ {
+ im[0] = explicit.getIcon(0);
+ im[1] = explicit.getIcon(1);
+ im[2] = explicit.getIcon(2);
+ im[3] = explicit.getIcon(3);
+ }
+ }
+ beanClass = beanClass.getSuperclass();
+ }
+
+ if(propertyStopClass == null)
+ {
+ propertyStopClass = stopClass;
+ }
+
+ if(eventStopClass == null)
+ {
+ eventStopClass = stopClass;
+ }
+
+ if(methodStopClass == null)
+ {
+ methodStopClass = stopClass;
+ }
+ }
+
+ /** Throws away all cached data and makes sure we re-instantiate things
+ * like BeanDescriptors again.
+ */
+ static void flushCaches() {
+ explicitBeanInfos.clear();
+ emptyBeanInfos.clear();
+ }
+
+ static BeanInfo findExplicitBeanInfo(Class beanClass)
+ {
+ BeanInfo retval = (BeanInfo)explicitBeanInfos.get(beanClass);
+ if(retval != null)
+ {
+ return retval;
+ }
+ else if(emptyBeanInfos.indexOf(beanClass) != -1)
+ {
+ return null;
+ }
+ else
+ {
+ retval = reallyFindExplicitBeanInfo(beanClass);
+ if(retval != null)
+ {
+ explicitBeanInfos.put(beanClass,retval);
+ }
+ else
+ {
+ emptyBeanInfos.addElement(beanClass);
+ }
+ return retval;
+ }
+ }
+
+ static BeanInfo reallyFindExplicitBeanInfo(Class beanClass)
+ {
+ ClassLoader beanClassLoader = beanClass.getClassLoader();
+ BeanInfo beanInfo;
+
+ beanInfo = getBeanInfo(beanClassLoader, beanClass.getName() + "BeanInfo");
+ if (beanInfo == null)
+ {
+ String newName;
+ newName = ClassHelper.getTruncatedClassName(beanClass) + "BeanInfo";
+
+ for(int i = 0; i < Introspector.beanInfoSearchPath.length; i++)
+ {
+ if (Introspector.beanInfoSearchPath[i].equals(""))
+ beanInfo = getBeanInfo(beanClassLoader, newName);
+ else
+ beanInfo = getBeanInfo(beanClassLoader,
+ Introspector.beanInfoSearchPath[i] + "."
+ + newName);
+
+ // Returns the beanInfo if it exists and the described class matches
+ // the one we searched.
+ if (beanInfo != null && beanInfo.getBeanDescriptor() != null &&
+ beanInfo.getBeanDescriptor().getBeanClass() == beanClass)
+
+ return beanInfo;
+ }
+ }
+
+ return beanInfo;
+ }
+
+ /**
+ * Returns an instance of the given class name when it can be loaded
+ * through the given class loader, or null otherwise.
+ */
+ private static BeanInfo getBeanInfo(ClassLoader cl, String infoName)
+ {
+ try
+ {
+ return (BeanInfo) Class.forName(infoName, true, cl).newInstance();
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ return null;
+ }
+ catch (IllegalAccessException iae)
+ {
+ return null;
+ }
+ catch (InstantiationException ie)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/java/beans/MethodDescriptor.java b/libjava/classpath/java/beans/MethodDescriptor.java
new file mode 100644
index 000000000..0185fde81
--- /dev/null
+++ b/libjava/classpath/java/beans/MethodDescriptor.java
@@ -0,0 +1,87 @@
+/* java.beans.MethodDescriptor
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.lang.reflect.Method;
+
+/** MethodDescriptor describes information about a JavaBeans method.
+ ** It's a fairly straightforward class (at least something in this
+ ** package is straightforward!).
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 26 Jul 1998
+ **/
+public class MethodDescriptor extends FeatureDescriptor {
+ private Method m;
+ private ParameterDescriptor[] parameterDescriptors;
+
+ /** Create a new MethodDescriptor.
+ ** This method sets the name to the name of the method (Method.getName()).
+ ** @param m the method it will represent.
+ **/
+ public MethodDescriptor(Method m) {
+ setName(m.getName());
+ this.m = m;
+ }
+
+ /** Create a new MethodDescriptor.
+ ** This method sets the name to the name of the method (Method.getName()).
+ ** @param m the method it will represent.
+ ** @param parameterDescriptors descriptions of the parameters (especially names).
+ **/
+ public MethodDescriptor(Method m, ParameterDescriptor[] parameterDescriptors) {
+ setName(m.getName());
+ this.m = m;
+ this.parameterDescriptors = parameterDescriptors;
+ }
+
+ /** Get the parameter descriptors from this method.
+ ** Since MethodDescriptor has no way of determining what
+ ** the parameter names were, this defaults to null.
+ **/
+ public ParameterDescriptor[] getParameterDescriptors() {
+ return parameterDescriptors;
+ }
+
+ /** Get the method this MethodDescriptor represents. **/
+ public Method getMethod() {
+ return m;
+ }
+}
diff --git a/libjava/classpath/java/beans/ParameterDescriptor.java b/libjava/classpath/java/beans/ParameterDescriptor.java
new file mode 100644
index 000000000..148690066
--- /dev/null
+++ b/libjava/classpath/java/beans/ParameterDescriptor.java
@@ -0,0 +1,52 @@
+/* java.beans.MethodDescriptor
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/** ParameterDescriptor represents a single parameter to a method.
+ ** As it turns out, FeatureDescriptor is sufficient to hold all
+ ** the information. Use its constructor and methods to set
+ ** the appropriate values.
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 26 Jul 1998
+ **/
+public class ParameterDescriptor extends FeatureDescriptor {
+
+}
diff --git a/libjava/classpath/java/beans/PersistenceDelegate.java b/libjava/classpath/java/beans/PersistenceDelegate.java
new file mode 100644
index 000000000..d4e777844
--- /dev/null
+++ b/libjava/classpath/java/beans/PersistenceDelegate.java
@@ -0,0 +1,90 @@
+/* java.beans.PersistenceDelegate
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+/** <p>A <code>PersistenceDelegate</code> describes how a another object
+ * has to constructed and transformed in order to create a complete
+ * replicate.</p>
+ *
+ * <p>For custom classes you will need to implement
+ * <code>PersistenceDelegate</code> in a way that is suitable for them.
+ * To make use of the implementation you have to register it with an
+ * {@link Encoder} using the {Encoder#setPersistenceDelegate} method.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.4
+ */
+public abstract class PersistenceDelegate
+{
+
+ protected void initialize(Class<?> type, Object oldInstance,
+ Object newInstance, Encoder out)
+ {
+ if (type != Object.class)
+ {
+ type = type.getSuperclass();
+
+ PersistenceDelegate pd = out.getPersistenceDelegate(type);
+
+ pd.initialize(type, oldInstance, newInstance, out);
+ }
+ }
+
+ public void writeObject(Object oldInstance, Encoder out)
+ {
+ Object streamCandidate = out.get(oldInstance);
+
+ if (mutatesTo(oldInstance, streamCandidate))
+ {
+ initialize(oldInstance.getClass(), oldInstance, streamCandidate, out);
+ }
+ else
+ {
+ out.remove(oldInstance);
+ out.writeExpression(instantiate(oldInstance, out));
+ }
+ }
+
+ protected boolean mutatesTo(Object oldInstance, Object newInstance)
+ {
+ return (newInstance != null)
+ && oldInstance.getClass() == newInstance.getClass();
+ }
+
+ protected abstract Expression instantiate(Object oldInstance, Encoder out);
+}
diff --git a/libjava/classpath/java/beans/PropertyChangeEvent.java b/libjava/classpath/java/beans/PropertyChangeEvent.java
new file mode 100644
index 000000000..3e3f948e3
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyChangeEvent.java
@@ -0,0 +1,189 @@
+/* PropertyChangeEvent.java -- describes a change in a property
+ Copyright (C) 1998, 2000, 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventObject;
+
+/**
+ * PropertyChangeEvents are fired in the PropertyChange and VetoableChange
+ * event classes. They represent the old and new values as well as the
+ * source Bean. If the old or new value is a primitive type, it must be
+ * wrapped in the appropriate wrapper type (java.lang.Integer for int, etc.,
+ * etc.).
+ *
+ * <p>If the old or new values are unknown (although why that would be I do
+ * not know), they may be null. Also, if the set of properties itself has
+ * changed, the name should be null, and the old and new values may also be
+ * null. Right now Sun put in a propagationId, reserved for future use. Read
+ * the comments on the constructor and on setPropagationId for more
+ * information.
+ *
+ * @author John Keiser
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.1
+ * @status udpated to 1.4
+ */
+public class PropertyChangeEvent extends EventObject
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 7042693688939648123L;
+
+ /**
+ * The name of the property that changed, may be null. Package visible for
+ * use by PropertyChangeSupport.
+ *
+ * @serial the changed property name
+ */
+ final String propertyName;
+
+ /**
+ * The new value of the property, may be null. Package visible for use by
+ * PropertyChangeSupport.
+ *
+ * @serial the new property value
+ */
+ final Object newValue;
+
+ /**
+ * The old value of the property, may be null. Package visible for use by
+ * PropertyChangeSupport.
+ *
+ * @serial the old property value
+ */
+ final Object oldValue;
+
+ /**
+ * The propagation ID, reserved for future use. May be null.
+ *
+ * @see #getPropagationId()
+ * @serial the Propagation ID
+ */
+ private Object propagationId;
+
+ /**
+ * Create a new PropertyChangeEvent. Remember that if you received a
+ * PropertyChangeEvent and are sending a new one, you should also set the
+ * propagation ID from the old PropertyChangeEvent.
+ *
+ * @param source the Bean containing the property
+ * @param propertyName the property's name
+ * @param oldVal the old value of the property
+ * @param newVal the new value of the property
+ * @throws IllegalArgumentException if source is null
+ */
+ public PropertyChangeEvent(Object source, String propertyName,
+ Object oldVal, Object newVal)
+ {
+ super(source);
+ this.propertyName = propertyName;
+ oldValue = oldVal;
+ newValue = newVal;
+ }
+
+ /**
+ * Get the property name. May be null if multiple properties changed.
+ *
+ * @return the property name
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+
+ /**
+ * Get the property's new value. May be null if multiple properties changed.
+ *
+ * @return the property's new value
+ */
+ public Object getNewValue()
+ {
+ return newValue;
+ }
+
+ /**
+ * Get the property's old value. May be null if multiple properties changed.
+ *
+ * @return the property's old value
+ */
+ public Object getOldValue()
+ {
+ return oldValue;
+ }
+
+ /**
+ * Set the propagation ID. This is a way for the event to be passed from
+ * hand to hand and retain a little extra state. Right now it is unused,
+ * but it should be propagated anyway so that future versions of JavaBeans
+ * can use it, for God knows what.
+ *
+ * @param propagationId the propagation ID
+ * @see #getPropagationId()
+ */
+ public void setPropagationId(Object propagationId)
+ {
+ this.propagationId = propagationId;
+ }
+
+ /**
+ * Get the propagation ID. Right now, it is not used for anything.
+ *
+ * @return the propagation ID
+ * @see #setPropagationId(Object)
+ */
+ public Object getPropagationId()
+ {
+ return propagationId;
+ }
+
+ /**
+ * Utility method to rollback a change.
+ *
+ * @param event the event to rollback
+ * @return a new event with old and new swapped
+ */
+ PropertyChangeEvent rollback()
+ {
+ PropertyChangeEvent result
+ = new PropertyChangeEvent(source, propertyName, newValue, oldValue);
+ result.propagationId = propagationId;
+ return result;
+ }
+} // class PropertyChangeEvent
diff --git a/libjava/classpath/java/beans/PropertyChangeListener.java b/libjava/classpath/java/beans/PropertyChangeListener.java
new file mode 100644
index 000000000..a97e6e1c2
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyChangeListener.java
@@ -0,0 +1,61 @@
+/* PropertyChangeListener.java -- listen for changes in a bound property
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventListener;
+
+/**
+ * PropertyChangeListener allows a class to monitor properties of a Bean for
+ * changes. A propertyChange() event will only be fired <em>after</em> the
+ * property has changed.
+ *
+ * @author John Keiser
+ * @see PropertyChangeSupport
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public interface PropertyChangeListener extends EventListener
+{
+ /**
+ * Fired after a Bean's property has changed.
+ *
+ * @param e the change (containing the old and new values)
+ */
+ void propertyChange(PropertyChangeEvent e);
+} // interface PropertyChangeListener
diff --git a/libjava/classpath/java/beans/PropertyChangeListenerProxy.java b/libjava/classpath/java/beans/PropertyChangeListenerProxy.java
new file mode 100644
index 000000000..68a815303
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyChangeListenerProxy.java
@@ -0,0 +1,102 @@
+/* PropertyChangeListenerProxy.java -- adds a name to a property listener
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * This class provides an extension to <code>PropertyChangeListener</code> -
+ * associating a name with the listener. This can be used to filter the
+ * changes that one is interested in.
+ *
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.4
+ * @status udpated to 1.4
+ */
+public class PropertyChangeListenerProxy extends EventListenerProxy
+ implements PropertyChangeListener
+{
+ /**
+ * The name of the property to listen for. Package visible for use by
+ * PropertyChangeSupport.
+ */
+ final String propertyName;
+
+ /**
+ * Create a new proxy which filters property change events and only passes
+ * changes to the named property on to the delegate. A null propertyName
+ * or listener does not fail now, but may cause a NullPointerException down
+ * the road.
+ *
+ * @param propertyName the property's name to filter on
+ * @param listener the delegate listener
+ */
+ public PropertyChangeListenerProxy(String propertyName,
+ PropertyChangeListener listener)
+ {
+ super(listener);
+ this.propertyName = propertyName;
+ }
+
+ /**
+ * Forwards the event on to the delegate if the property name matches.
+ *
+ * @param event the event to pass on, if it meets the filter
+ * @throws NullPointerException if the delegate this was created with is null
+ */
+ public void propertyChange(PropertyChangeEvent event)
+ {
+ // Note: Sun does not filter, under the assumption that since
+ // PropertyChangeSupport unwraps proxys, this method should never be
+ // called by normal use of listeners.
+ String name = event == null ? null : event.getPropertyName();
+ if (name == null ? propertyName == null : name.equals(propertyName))
+ ((PropertyChangeListener) getListener()).propertyChange(event);
+ }
+
+ /**
+ * Gets the name of the property this proxy is filtering on.
+ *
+ * @return the property name
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+} // class PropertyChangeListenerProxy
diff --git a/libjava/classpath/java/beans/PropertyChangeSupport.java b/libjava/classpath/java/beans/PropertyChangeSupport.java
new file mode 100644
index 000000000..3f3f53d42
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyChangeSupport.java
@@ -0,0 +1,545 @@
+/* PropertyChangeSupport.java -- support to manage property change listeners
+ Copyright (C) 1998, 1999, 2000, 2002, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+/**
+ * PropertyChangeSupport makes it easy to fire property change events and
+ * handle listeners. It allows chaining of listeners, as well as filtering
+ * by property name. In addition, it will serialize only those listeners
+ * which are serializable, ignoring the others without problem. This class
+ * is thread-safe.
+ *
+ * @author John Keiser
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class PropertyChangeSupport implements Serializable
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 6401253773779951803L;
+
+ /**
+ * Maps property names (String) to named listeners (PropertyChangeSupport).
+ * If this is a child instance, this field will be null.
+ *
+ * @serial the map of property names to named listener managers
+ * @since 1.2
+ */
+ private Hashtable children;
+
+ /**
+ * The non-null source object for any generated events.
+ *
+ * @serial the event source
+ */
+ private final Object source;
+
+ /**
+ * A field to compare serialization versions - this class uses version 2.
+ *
+ * @serial the serialization format
+ */
+ private static final int propertyChangeSupportSerializedDataVersion = 2;
+
+ /**
+ * The list of all registered property listeners. If this instance was
+ * created by user code, this only holds the global listeners (ie. not tied
+ * to a name), and may be null. If it was created by this class, as a
+ * helper for named properties, then this vector will be non-null, and this
+ * instance appears as a value in the <code>children</code> hashtable of
+ * another instance, so that the listeners are tied to the key of that
+ * hashtable entry.
+ */
+ private transient Vector listeners;
+
+ /**
+ * Create a PropertyChangeSupport to work with a specific source bean.
+ *
+ * @param source the source bean to use
+ * @throws NullPointerException if source is null
+ */
+ public PropertyChangeSupport(Object source)
+ {
+ this.source = source;
+ if (source == null)
+ throw new NullPointerException();
+ }
+
+ /**
+ * Adds a PropertyChangeListener to the list of global listeners. All
+ * property change events will be sent to this listener. The listener add
+ * is not unique: that is, <em>n</em> adds with the same listener will
+ * result in <em>n</em> events being sent to that listener for every
+ * property change. Adding a null listener is silently ignored.
+ * This method will unwrap a PropertyChangeListenerProxy,
+ * registering the underlying delegate to the named property list.
+ *
+ * @param l the listener to add
+ */
+ public synchronized void addPropertyChangeListener(PropertyChangeListener l)
+ {
+ if (l == null)
+ return;
+
+ if (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ addPropertyChangeListener(p.propertyName,
+ (PropertyChangeListener) p.getListener());
+ }
+ else
+ {
+ if (listeners == null)
+ listeners = new Vector();
+ listeners.add(l);
+ }
+ }
+
+ /**
+ * Removes a PropertyChangeListener from the list of global listeners. If
+ * any specific properties are being listened on, they must be deregistered
+ * by themselves; this will only remove the general listener to all
+ * properties. If <code>add()</code> has been called multiple times for a
+ * particular listener, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * PropertyChangeListenerProxy, removing the underlying delegate from the
+ * named property list.
+ *
+ * @param l the listener to remove
+ */
+ public synchronized void
+ removePropertyChangeListener(PropertyChangeListener l)
+ {
+ if (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ removePropertyChangeListener(p.propertyName,
+ (PropertyChangeListener) p.getListener());
+ }
+ else if (listeners != null)
+ {
+ listeners.remove(l);
+ if (listeners.isEmpty())
+ listeners = null;
+ }
+ }
+
+ /**
+ * Returns an array of all registered property change listeners. Those that
+ * were registered under a name will be wrapped in a
+ * <code>PropertyChangeListenerProxy</code>, so you must check whether the
+ * listener is an instance of the proxy class in order to see what name the
+ * real listener is registered under. If there are no registered listeners,
+ * this returns an empty array.
+ *
+ * @return the array of registered listeners
+ * @see PropertyChangeListenerProxy
+ * @since 1.4
+ */
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners()
+ {
+ ArrayList list = new ArrayList();
+ if (listeners != null)
+ list.addAll(listeners);
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ Vector v = ((PropertyChangeSupport) e.getValue()).listeners;
+ int j = v.size();
+ while (--j >= 0)
+ list.add(new PropertyChangeListenerProxy
+ (name, (PropertyChangeListener) v.get(j)));
+ }
+ }
+ return (PropertyChangeListener[])
+ list.toArray(new PropertyChangeListener[list.size()]);
+ }
+
+ /**
+ * Adds a PropertyChangeListener listening on the specified property. Events
+ * will be sent to the listener only if the property name matches. The
+ * listener add is not unique; that is, <em>n</em> adds on a particular
+ * property for a particular listener will result in <em>n</em> events
+ * being sent to that listener when that property is changed. The effect is
+ * cumulative, too; if you are registered to listen to receive events on
+ * all property changes, and then you register on a particular property,
+ * you will receive change events for that property twice. Adding a null
+ * listener is silently ignored. This method will unwrap a
+ * PropertyChangeListenerProxy, registering the underlying
+ * delegate to the named property list if the names match, and discarding
+ * it otherwise.
+ *
+ * @param propertyName the name of the property to listen on
+ * @param l the listener to add
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener l)
+ {
+ if (l == null)
+ return;
+
+ while (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (PropertyChangeListener) p.getListener();
+ }
+ PropertyChangeSupport s = null;
+ if (children == null)
+ children = new Hashtable();
+ else
+ s = (PropertyChangeSupport) children.get(propertyName);
+ if (s == null)
+ {
+ s = new PropertyChangeSupport(source);
+ s.listeners = new Vector();
+ children.put(propertyName, s);
+ }
+ s.listeners.add(l);
+ }
+
+ /**
+ * Removes a PropertyChangeListener from listening to a specific property.
+ * If <code>add()</code> has been called multiple times for a particular
+ * listener on a property, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * PropertyChangeListenerProxy, removing the underlying delegate from the
+ * named property list if the names match.
+ *
+ * @param propertyName the property to stop listening on
+ * @param l the listener to remove
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void
+ removePropertyChangeListener(String propertyName, PropertyChangeListener l)
+ {
+ if (children == null)
+ return;
+ PropertyChangeSupport s
+ = (PropertyChangeSupport) children.get(propertyName);
+ if (s == null)
+ return;
+ while (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (PropertyChangeListener) p.getListener();
+ }
+ s.listeners.remove(l);
+ if (s.listeners.isEmpty())
+ {
+ children.remove(propertyName);
+ if (children.isEmpty())
+ children = null;
+ }
+ }
+
+ /**
+ * Returns an array of all property change listeners registered under the
+ * given property name. If there are no registered listeners, or
+ * propertyName is null, this returns an empty array.
+ *
+ * @return the array of registered listeners
+ * @since 1.4
+ */
+ public synchronized PropertyChangeListener[]
+ getPropertyChangeListeners(String propertyName)
+ {
+ if (children == null || propertyName == null)
+ return new PropertyChangeListener[0];
+ PropertyChangeSupport s
+ = (PropertyChangeSupport) children.get(propertyName);
+ if (s == null)
+ return new PropertyChangeListener[0];
+ return (PropertyChangeListener[])
+ s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]);
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are non-null
+ * and equal.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ */
+ public void firePropertyChange(String propertyName,
+ Object oldVal, Object newVal)
+ {
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ oldVal, newVal));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ */
+ public void firePropertyChange(String propertyName, int oldVal, int newVal)
+ {
+ if (oldVal != newVal)
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ Integer.valueOf(oldVal),
+ Integer.valueOf(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ */
+ public void firePropertyChange(String propertyName,
+ boolean oldVal, boolean newVal)
+ {
+ if (oldVal != newVal)
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ Boolean.valueOf(oldVal),
+ Boolean.valueOf(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent to all the global listeners, and to all the
+ * listeners for the specified property name. This does nothing if old and
+ * new values of the event are equal.
+ *
+ * @param event the event to fire
+ * @throws NullPointerException if event is null
+ */
+ public void firePropertyChange(PropertyChangeEvent event)
+ {
+ if (event.oldValue != null && event.oldValue.equals(event.newValue))
+ return;
+ Vector v = listeners; // Be thread-safe.
+ if (v != null)
+ {
+ int i = v.size();
+ while (--i >= 0)
+ ((PropertyChangeListener) v.get(i)).propertyChange(event);
+ }
+ Hashtable h = children; // Be thread-safe.
+ if (h != null && event.propertyName != null)
+ {
+ PropertyChangeSupport s
+ = (PropertyChangeSupport) h.get(event.propertyName);
+ if (s != null)
+ {
+ v = s.listeners; // Be thread-safe.
+ int i = v == null ? 0 : v.size();
+ while (--i >= 0)
+ ((PropertyChangeListener) v.get(i)).propertyChange(event);
+ }
+ }
+ }
+
+ /**
+ * Fire an indexed property change event. This will only fire
+ * an event if the old and new values are not equal and not null.
+ * @param name the name of the property which changed
+ * @param index the index of the property which changed
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
+ * @since 1.5
+ */
+ public void fireIndexedPropertyChange(String name, int index,
+ Object oldValue, Object newValue)
+ {
+ // Argument checking is done in firePropertyChange(PropertyChangeEvent) .
+ firePropertyChange(new IndexedPropertyChangeEvent(source, name,
+ oldValue, newValue,
+ index));
+ }
+
+ /**
+ * Fire an indexed property change event. This will only fire
+ * an event if the old and new values are not equal.
+ * @param name the name of the property which changed
+ * @param index the index of the property which changed
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
+ * @since 1.5
+ */
+ public void fireIndexedPropertyChange(String name, int index,
+ int oldValue, int newValue)
+ {
+ if (oldValue != newValue)
+ fireIndexedPropertyChange(name, index, Integer.valueOf(oldValue),
+ Integer.valueOf(newValue));
+ }
+
+ /**
+ * Fire an indexed property change event. This will only fire
+ * an event if the old and new values are not equal.
+ * @param name the name of the property which changed
+ * @param index the index of the property which changed
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
+ * @since 1.5
+ */
+ public void fireIndexedPropertyChange(String name, int index,
+ boolean oldValue, boolean newValue)
+ {
+ if (oldValue != newValue)
+ fireIndexedPropertyChange(name, index, Boolean.valueOf(oldValue),
+ Boolean.valueOf(newValue));
+ }
+
+ /**
+ * Tell whether the specified property is being listened on or not. This
+ * will only return <code>true</code> if there are listeners on all
+ * properties or if there is a listener specifically on this property.
+ *
+ * @param propertyName the property that may be listened on
+ * @return whether the property is being listened on
+ */
+ public synchronized boolean hasListeners(String propertyName)
+ {
+ return listeners != null || (children != null
+ && children.get(propertyName) != null);
+ }
+
+ /**
+ * Saves the state of the object to the stream.
+ *
+ * @param s the stream to write to
+ * @throws IOException if anything goes wrong
+ * @serialData this writes out a null-terminated list of serializable
+ * global property change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private synchronized void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+ if (listeners != null)
+ {
+ int i = listeners.size();
+ while (--i >= 0)
+ if (listeners.get(i) instanceof Serializable)
+ s.writeObject(listeners.get(i));
+ }
+ s.writeObject(null);
+ }
+
+ /**
+ * Reads the object back from stream (deserialization).
+ *
+ * XXX Since serialization for 1.1 streams was not documented, this may
+ * not work if propertyChangeSupportSerializedDataVersion is 1.
+ *
+ * @param s the stream to read from
+ * @throws IOException if reading the stream fails
+ * @throws ClassNotFoundException if deserialization fails
+ * @serialData this reads in a null-terminated list of serializable
+ * global property change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ PropertyChangeListener l = (PropertyChangeListener) s.readObject();
+ while (l != null)
+ {
+ addPropertyChangeListener(l);
+ l = (PropertyChangeListener) s.readObject();
+ }
+ // Sun is not as careful with children as we are, and lets some proxys
+ // in that can never receive events. So, we clean up anything that got
+ // serialized, to make sure our invariants hold.
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ PropertyChangeSupport pcs = (PropertyChangeSupport) e.getValue();
+ if (pcs.listeners == null)
+ pcs.listeners = new Vector();
+ if (pcs.children != null)
+ pcs.listeners.addAll
+ (Arrays.asList(pcs.getPropertyChangeListeners(name)));
+ if (pcs.listeners.size() == 0)
+ iter.remove();
+ else
+ pcs.children = null;
+ }
+ if (children.size() == 0)
+ children = null;
+ }
+ }
+} // class PropertyChangeSupport
diff --git a/libjava/classpath/java/beans/PropertyDescriptor.java b/libjava/classpath/java/beans/PropertyDescriptor.java
new file mode 100644
index 000000000..a74fa7b13
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyDescriptor.java
@@ -0,0 +1,665 @@
+/* java.beans.PropertyDescriptor
+ Copyright (C) 1998, 2001, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ ** PropertyDescriptor describes information about a JavaBean property,
+ ** by which we mean a property that has been exposed via a pair of
+ ** get and set methods. (There may be no get method, which means
+ ** the property is write-only, or no set method, which means the
+ ** the property is read-only.)<P>
+ **
+ ** The constraints put on get and set methods are:<P>
+ ** <OL>
+ ** <LI>A get method must have signature
+ ** <CODE>&lt;propertyType&gt; &lt;getMethodName&gt;()</CODE></LI>
+ ** <LI>A set method must have signature
+ ** <CODE>void &lt;setMethodName&gt;(&lt;propertyType&gt;)</CODE></LI>
+ ** <LI>Either method type may throw any exception.</LI>
+ ** <LI>Both methods must be public.</LI>
+ ** </OL>
+ **
+ ** @author John Keiser
+ ** @author Robert Schuster (thebohemian@gmx.net)
+ ** @since 1.1
+ ** @status updated to 1.4
+ **/
+public class PropertyDescriptor extends FeatureDescriptor
+{
+ Class<?> propertyType;
+ Method getMethod;
+ Method setMethod;
+
+ Class<?> propertyEditorClass;
+ boolean bound;
+ boolean constrained;
+
+ PropertyDescriptor(String name)
+ {
+ setName(name);
+ }
+
+ /** Create a new PropertyDescriptor by introspection.
+ ** This form of constructor creates the PropertyDescriptor by
+ ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>
+ ** (or, optionally, if the property is boolean,
+ ** <CODE>is&lt;name&gt;()</CODE>) and
+ ** <CODE>set&lt;name&gt;()</CODE> in class
+ ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
+ ** first letter capitalized by the constructor.<P>
+ **
+ ** Note that using this constructor the given property must be read- <strong>and</strong>
+ ** writeable. If the implementation does not both, a read and a write method, an
+ ** <code>IntrospectionException</code> is thrown.
+ **
+ ** <B>Implementation note:</B> If there is both are both isXXX and
+ ** getXXX methods, the former is used in preference to the latter.
+ ** We do not check that an isXXX method returns a boolean. In both
+ ** cases, this matches the behaviour of JDK 1.4<P>
+ **
+ ** @param name the programmatic name of the property, usually
+ ** starting with a lowercase letter (e.g. fooManChu
+ ** instead of FooManChu).
+ ** @param beanClass the class the get and set methods live in.
+ ** @exception IntrospectionException if the methods are not found
+ ** or invalid.
+ **/
+ public PropertyDescriptor(String name, Class<?> beanClass)
+ throws IntrospectionException
+ {
+ setName(name);
+ if (name.length() == 0)
+ {
+ throw new IntrospectionException("empty property name");
+ }
+ String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps);
+
+ if (getMethod == null)
+ {
+ throw new IntrospectionException(
+ "Cannot find a is" + caps + " or get" + caps + " method");
+ }
+
+ if (setMethod == null)
+ {
+ throw new IntrospectionException(
+ "Cannot find a " + caps + " method");
+ }
+
+ // finally check the methods compatibility
+ propertyType = checkMethods(getMethod, setMethod);
+ }
+
+ /** Create a new PropertyDescriptor by introspection.
+ ** This form of constructor allows you to specify the
+ ** names of the get and set methods to search for.<P>
+ **
+ ** <B>Implementation note:</B> If there is a get method (or
+ ** boolean isXXX() method), then the return type of that method
+ ** is used to find the set method. If there is no get method,
+ ** then the set method is searched for exhaustively.<P>
+ **
+ ** <B>Spec note:</B>
+ ** If there is no get method and multiple set methods with
+ ** the same name and a single parameter (different type of course),
+ ** then an IntrospectionException is thrown. While Sun's spec
+ ** does not state this, it can make Bean behavior different on
+ ** different systems (since method order is not guaranteed) and as
+ ** such, can be treated as a bug in the spec. I am not aware of
+ ** whether Sun's implementation catches this.
+ **
+ ** @param name the programmatic name of the property, usually
+ ** starting with a lowercase letter (e.g. fooManChu
+ ** instead of FooManChu).
+ ** @param beanClass the class the get and set methods live in.
+ ** @param getMethodName the name of the get method or <code>null</code> if the property is write-only.
+ ** @param setMethodName the name of the set method or <code>null</code> if the property is read-only.
+ ** @exception IntrospectionException if the methods are not found
+ ** or invalid.
+ **/
+ public PropertyDescriptor(
+ String name,
+ Class<?> beanClass,
+ String getMethodName,
+ String setMethodName)
+ throws IntrospectionException
+ {
+ setName(name);
+ findMethods(beanClass, getMethodName, null, setMethodName);
+
+ if (getMethod == null && getMethodName != null)
+ {
+ throw new IntrospectionException(
+ "Cannot find a getter method called " + getMethodName);
+ }
+
+ if (setMethod == null && setMethodName != null)
+ {
+ throw new IntrospectionException(
+ "Cannot find a setter method called " + setMethodName);
+ }
+
+ propertyType = checkMethods(getMethod, setMethod);
+ }
+
+ /** Create a new PropertyDescriptor using explicit Methods.
+ ** Note that the methods will be checked for conformance to standard
+ ** Property method rules, as described above at the top of this class.
+ **<br>
+ ** It is possible to call this method with both <code>Method</code> arguments
+ ** being <code>null</code>. In such a case the property type is <code>null</code>.
+ **
+ ** @param name the programmatic name of the property, usually
+ ** starting with a lowercase letter (e.g. fooManChu
+ ** instead of FooManChu).
+ ** @param readMethod the read method or <code>null</code> if the property is write-only.
+ ** @param writeMethod the write method or <code>null</code> if the property is read-only.
+ ** @exception IntrospectionException if the methods are not found
+ ** or invalid.
+ **/
+ public PropertyDescriptor(
+ String name,
+ Method readMethod,
+ Method writeMethod)
+ throws IntrospectionException
+ {
+ setName(name);
+ getMethod = readMethod;
+ setMethod = writeMethod;
+ propertyType = checkMethods(getMethod, setMethod);
+ }
+
+ /** Get the property type.
+ ** This is the type the get method returns and the set method
+ ** takes in.
+ **/
+ public Class<?> getPropertyType()
+ {
+ return propertyType;
+ }
+
+ /** Get the get method. Why they call it readMethod here and
+ ** get everywhere else is beyond me.
+ **/
+ public Method getReadMethod()
+ {
+ return getMethod;
+ }
+
+ /** Sets the read method.<br/>
+ * The read method is used to retrieve the value of a property. A legal
+ * read method must have no arguments. Its return type must not be
+ * <code>void</code>. If this methods succeeds the property type
+ * is adjusted to the return type of the read method.<br/>
+ * <br/>
+ * It is legal to set the read and the write method to <code>null</code>
+ * or provide method which have been declared in distinct classes.
+ *
+ * @param readMethod The new method to be used or <code>null</code>.
+ * @throws IntrospectionException If the given method is invalid.
+ * @since 1.2
+ */
+ public void setReadMethod(Method readMethod) throws IntrospectionException
+ {
+ propertyType = checkMethods(readMethod, setMethod);
+
+ getMethod = readMethod;
+ }
+
+ /** Get the set method. Why they call it writeMethod here and
+ ** set everywhere else is beyond me.
+ **/
+ public Method getWriteMethod()
+ {
+ return setMethod;
+ }
+
+ /** Sets the write method.<br/>
+ * The write method is used to set the value of a property. A legal write method
+ * must have a single argument which can be assigned to the property. If no
+ * read method exists the property type changes to the argument type of the
+ * write method.<br/>
+ * <br/>
+ * It is legal to set the read and the write method to <code>null</code>
+ * or provide method which have been declared in distinct classes.
+ *
+ * @param writeMethod The new method to be used or <code>null</code>.
+ * @throws IntrospectionException If the given method is invalid.
+ * @since 1.2
+ */
+ public void setWriteMethod(Method writeMethod)
+ throws IntrospectionException
+ {
+ propertyType = checkMethods(getMethod, writeMethod);
+
+ setMethod = writeMethod;
+ }
+
+ /** Get whether the property is bound. Defaults to false. **/
+ public boolean isBound()
+ {
+ return bound;
+ }
+
+ /** Set whether the property is bound.
+ ** As long as the the bean implements addPropertyChangeListener() and
+ ** removePropertyChangeListener(), setBound(true) may safely be called.<P>
+ ** If these things are not true, then the behavior of the system
+ ** will be undefined.<P>
+ **
+ ** When a property is bound, its set method is required to fire the
+ ** <CODE>PropertyChangeListener.propertyChange())</CODE> event
+ ** after the value has changed.
+ ** @param bound whether the property is bound or not.
+ **/
+ public void setBound(boolean bound)
+ {
+ this.bound = bound;
+ }
+
+ /** Get whether the property is constrained. Defaults to false. **/
+ public boolean isConstrained()
+ {
+ return constrained;
+ }
+
+ /** Set whether the property is constrained.
+ ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>
+ ** (or subclass thereof) and the bean implements addVetoableChangeListener()
+ ** and removeVetoableChangeListener(), then setConstrained(true) may safely
+ ** be called. Otherwise, the system behavior is undefined.
+ ** <B>Spec note:</B> given those strict parameters, it would be nice if it
+ ** got set automatically by detection, but oh well.<P>
+ ** When a property is constrained, its set method is required to:<P>
+ ** <OL>
+ ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>
+ ** event notifying others of the change and allowing them a chance to
+ ** say it is a bad thing.</LI>
+ ** <LI>If any of the listeners throws a PropertyVetoException, then
+ ** it must fire another vetoableChange() event notifying the others
+ ** of a reversion to the old value (though, of course, the change
+ ** was never made). Then it rethrows the PropertyVetoException and
+ ** exits.</LI>
+ ** <LI>If all has gone well to this point, the value may be changed.</LI>
+ ** </OL>
+ ** @param constrained whether the property is constrained or not.
+ **/
+ public void setConstrained(boolean constrained)
+ {
+ this.constrained = constrained;
+ }
+
+ /** Get the PropertyEditor class. Defaults to null. **/
+ public Class<?> getPropertyEditorClass()
+ {
+ return propertyEditorClass;
+ }
+
+ /** Set the PropertyEditor class. If the class does not implement
+ ** the PropertyEditor interface, you will likely get an exception
+ ** late in the game.
+ ** @param propertyEditorClass the PropertyEditor class for this
+ ** class to use.
+ **/
+ public void setPropertyEditorClass(Class<?> propertyEditorClass)
+ {
+ this.propertyEditorClass = propertyEditorClass;
+ }
+
+ /**
+ * Instantiate a property editor using the property editor class.
+ * If no property editor class has been set, this will return null.
+ * If the editor class has a public constructor which takes a single
+ * argument, that will be used and the bean parameter will be passed
+ * to it. Otherwise, a public no-argument constructor will be used,
+ * if available. This method will return null if no constructor is
+ * found or if construction fails for any reason.
+ * @param bean the argument to the constructor
+ * @return a new PropertyEditor, or null on error
+ * @since 1.5
+ */
+ public PropertyEditor createPropertyEditor(Object bean)
+ {
+ if (propertyEditorClass == null)
+ return null;
+ Constructor c = findConstructor(propertyEditorClass,
+ new Class[] { Object.class });
+ if (c != null)
+ return instantiateClass(c, new Object[] { bean });
+ c = findConstructor(propertyEditorClass, null);
+ if (c != null)
+ return instantiateClass(c, null);
+ return null;
+ }
+
+ // Helper method to look up a constructor and return null if it is not
+ // found.
+ private Constructor findConstructor(Class k, Class[] argTypes)
+ {
+ try
+ {
+ return k.getConstructor(argTypes);
+ }
+ catch (NoSuchMethodException _)
+ {
+ return null;
+ }
+ }
+
+ // Helper method to instantiate an object but return null on error.
+ private PropertyEditor instantiateClass(Constructor c, Object[] args)
+ {
+ try
+ {
+ return (PropertyEditor) c.newInstance(args);
+ }
+ catch (InstantiationException _)
+ {
+ return null;
+ }
+ catch (InvocationTargetException _)
+ {
+ return null;
+ }
+ catch (IllegalAccessException _)
+ {
+ return null;
+ }
+ catch (ClassCastException _)
+ {
+ return null;
+ }
+ }
+
+ private void findMethods(
+ Class beanClass,
+ String getMethodName1,
+ String getMethodName2,
+ String setMethodName)
+ throws IntrospectionException
+ {
+ try
+ {
+ // Try the first get method name
+ if (getMethodName1 != null)
+ {
+ try
+ {
+ getMethod =
+ beanClass.getMethod(getMethodName1, new Class[0]);
+ }
+ catch (NoSuchMethodException e)
+ {}
+ }
+
+ // Fall back to the second get method name
+ if (getMethod == null && getMethodName2 != null)
+ {
+ try
+ {
+ getMethod =
+ beanClass.getMethod(getMethodName2, new Class[0]);
+ }
+ catch (NoSuchMethodException e)
+ {}
+ }
+
+ // Try the set method name
+ if (setMethodName != null)
+ {
+ if (getMethod != null)
+ {
+ // If there is a get method, use its return type to help
+ // select the corresponding set method.
+ Class propertyType = getMethod.getReturnType();
+ if (propertyType == Void.TYPE)
+ {
+ String msg =
+ "The property's read method has return type 'void'";
+ throw new IntrospectionException(msg);
+ }
+
+ Class[] setArgs = new Class[] { propertyType };
+ try
+ {
+ setMethod = beanClass.getMethod(setMethodName, setArgs);
+ }
+ catch (NoSuchMethodException e)
+ {}
+ }
+ else if (getMethodName1 == null && getMethodName2 == null)
+ {
+ // If this is a write-only property, choose the first set method
+ // with the required name, one parameter and return type 'void'
+ Method[] methods = beanClass.getMethods();
+ for (int i = 0; i < methods.length; i++)
+ {
+ if (methods[i].getName().equals(setMethodName)
+ && methods[i].getParameterTypes().length == 1
+ && methods[i].getReturnType() == Void.TYPE)
+ {
+ setMethod = methods[i];
+ break;
+ }
+ }
+ }
+ }
+ }
+ catch (SecurityException e)
+ {
+ // FIXME -- shouldn't we just allow SecurityException to propagate?
+ String msg =
+ "SecurityException thrown on attempt to access methods.";
+ throw new IntrospectionException(msg);
+ }
+ }
+
+ /** Checks whether the given <code>Method</code> instances are legal read and
+ * write methods. The following requirements must be met:<br/>
+ * <ul>
+ * <li>the read method must not have an argument</li>
+ * <li>the read method must have a non void return type</li>
+ * <li>the read method may not exist</li>
+ * <li>the write method must have a single argument</li>
+ * <li>the property type and the read method's return type must be assignable from the
+ * write method's argument type</li>
+ * <li>the write method may not exist</li>
+ * </ul>
+ * While checking the methods a common new property type is calculated. If the method
+ * succeeds this property type is returned.<br/>
+ * <br/>
+ * For compatibility this has to be noted:<br/>
+ * The two methods are allowed to be defined in two distinct classes and may both be null.
+ *
+ * @param readMethod The new read method to check.
+ * @param writeMethod The new write method to check.
+ * @return The common property type of the two method.
+ * @throws IntrospectionException If any of the above requirements are not met.
+ */
+ private Class<?> checkMethods(Method readMethod, Method writeMethod)
+ throws IntrospectionException
+ {
+ Class<?> newPropertyType = propertyType;
+
+ // a valid read method has zero arguments and a non-void return type.
+ if (readMethod != null)
+ {
+ if (readMethod.getParameterTypes().length > 0)
+ {
+ throw new IntrospectionException("read method has unexpected parameters");
+ }
+
+ newPropertyType = readMethod.getReturnType();
+
+ if (newPropertyType == Void.TYPE)
+ {
+ throw new IntrospectionException("read method return type is void");
+ }
+ }
+
+ // a valid write method has one argument which can be assigned to the property
+ if (writeMethod != null)
+ {
+ if (writeMethod.getParameterTypes().length != 1)
+ {
+ String msg = "write method does not have exactly one parameter";
+ throw new IntrospectionException(msg);
+ }
+
+ if (readMethod == null)
+ {
+ // changes the property type if there is no read method
+ newPropertyType = writeMethod.getParameterTypes()[0];
+ }
+ else
+ {
+ // checks whether the write method can be assigned to the return type of the read
+ // method (if this is not the case, the methods are not compatible)
+ // note: newPropertyType may be null if no methods or method names have been
+ // delivered in the constructor.
+ if (newPropertyType != null
+ && !newPropertyType.isAssignableFrom(
+ writeMethod.getParameterTypes()[0]))
+ {
+ // note: newPropertyType is the same as readMethod.getReturnType() at this point
+ throw new IntrospectionException("read and write method are not compatible");
+ }
+
+ /* note: the check whether both method are defined in related classes makes sense but is not
+ * done in the JDK.
+ * I leave this code here in case someone at Sun decides to add that functionality in later versions (rschuster)
+ if ((!readMethod
+ .getDeclaringClass()
+ .isAssignableFrom(writeMethod.getDeclaringClass()))
+ && (!writeMethod
+ .getDeclaringClass()
+ .isAssignableFrom(readMethod.getDeclaringClass())))
+ {
+ String msg =
+ "set and get methods are not in the same class.";
+ throw new IntrospectionException(msg);
+ }
+ */
+
+ }
+ }
+
+ return newPropertyType;
+ }
+
+ /**
+ * Return a hash code for this object, conforming to the contract described
+ * in {@link Object#hashCode()}.
+ * @return the hash code
+ * @since 1.5
+ */
+ public int hashCode()
+ {
+ return ((propertyType == null ? 0 : propertyType.hashCode())
+ | (propertyEditorClass == null ? 0 : propertyEditorClass.hashCode())
+ | (bound ? Boolean.TRUE : Boolean.FALSE).hashCode()
+ | (constrained ? Boolean.TRUE : Boolean.FALSE).hashCode()
+ | (getMethod == null ? 0 : getMethod.hashCode())
+ | (setMethod == null ? 0 : setMethod.hashCode()));
+ }
+
+ /** Compares this <code>PropertyDescriptor</code> against the
+ * given object.
+ * Two PropertyDescriptors are equals if
+ * <ul>
+ * <li>the read methods are equal</li>
+ * <li>the write methods are equal</li>
+ * <li>the property types are equals</li>
+ * <li>the property editor classes are equal</li>
+ * <li>the flags (constrained and bound) are equal</li>
+ * </ul>
+ * @return Whether both objects are equal according to the rules given above.
+ * @since 1.4
+ */
+ public boolean equals(Object o)
+ {
+ if (o instanceof PropertyDescriptor)
+ {
+ PropertyDescriptor that = (PropertyDescriptor) o;
+
+ // compares the property types and checks the case where both are null
+ boolean samePropertyType =
+ (propertyType == null)
+ ? that.propertyType == null
+ : propertyType.equals(that.propertyType);
+
+ // compares the property editor classes and checks the case where both are null
+ boolean samePropertyEditorClass =
+ (propertyEditorClass == null)
+ ? that.propertyEditorClass == null
+ : propertyEditorClass.equals(that.propertyEditorClass);
+
+ // compares the flags for equality
+ boolean sameFlags =
+ bound == that.bound && constrained == that.constrained;
+
+ // compares the read methods and checks the case where both are null
+ boolean sameReadMethod =
+ (getMethod == null)
+ ? that.getMethod == null
+ : getMethod.equals(that.getMethod);
+
+ boolean sameWriteMethod =
+ (setMethod == null)
+ ? that.setMethod == null
+ : setMethod.equals(that.setMethod);
+
+ return samePropertyType
+ && sameFlags
+ && sameReadMethod
+ && sameWriteMethod
+ && samePropertyEditorClass;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+
+}
diff --git a/libjava/classpath/java/beans/PropertyEditor.java b/libjava/classpath/java/beans/PropertyEditor.java
new file mode 100644
index 000000000..5fba014ea
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyEditor.java
@@ -0,0 +1,209 @@
+/* java.beans.PropertyEditor
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ ** PropertyEditors are custom GUI editors for specific types of values.
+ **
+ ** A PropertyEditor can be used, for example, if you are editing a type of value
+ ** that can be more easily represented graphically, such as a Point, or one that
+ ** can be more easily represented by a list, such as a boolean (true/false).<P>
+ **
+ ** A PropertyEditor must be able to display its contents when asked to and
+ ** be able to allow the user to change its underlying field value. However, it
+ ** is not the PropertyEditor's responsibility to make the change to the
+ ** underlying Object; in fact, the PropertyEditor does not even know about the
+ ** Object it is actually editing--only about the property it is currently
+ ** editing. When a change is made to the property, the PropertyEditor must
+ ** simply fire a PropertyChangeEvent and allow the RAD tool to actually set
+ ** the property in the underlying Bean.<P>
+ **
+ ** PropertyEditors should not change the Objects they are given by setValue().
+ ** These Objects may or may not be the actual Objects which are properties of
+ ** the Bean being edited. Instead, PropertyEditors should create a new Object
+ ** and fire a PropertyChangeEvent with the old and new values.<P>
+ **
+ ** PropertyEditors also must support the ability to return a Java
+ ** initialization string. See the getJavaInitializationString() method for
+ ** details.<P>
+ **
+ ** There are several different ways a PropertyEditor may display and control
+ ** editing of its value. When multiple types of input and display are
+ ** given by a single PropertyEditor, the RAD tool may decide which of the call
+ ** to support. Some RAD tools may even be text-only, so even if you support
+ ** a graphical set and get, it may choose the text set and get whenever it can.
+ ** <OL>
+ ** <LI>Every PropertyEditor must support getValue() and setValue(). For
+ ** setValue(), the component must only support it when the argument is
+ ** the same type that the PropertyEditor supports.</LI>
+ ** <LI>Every PropertyEditor must support getJavaInitializationString().</LI>
+ ** <LI>You may support painting the value yourself if you wish. To do this,
+ ** have isPaintable() return true and implement the paintValue() method.
+ ** This method does not determine in any way how the value is edited;
+ ** merely how it is displayed.</LI>
+ ** <LI>Let the caller of the PropertyEditor give the user a text input. Do
+ ** this by returning a non-null String from getAsText(). If you support
+ ** text input, you *must* support setAsText().</LI>
+ ** <LI>Give the caller a set of possible values, such as "true"/"false", that
+ ** the user must select from. To do this, return the list of Strings
+ ** from the getTags() method. The RAD tool may choose to implement the
+ ** user input any way it wishes, and only guarantees that setAsText() will
+ ** only be called with one of the Strings returned from getTags().</LI>
+ ** <LI>You may support a whole custom editing control by supporting
+ ** getCustomEditor(). To do this, return true from supportsCustomEditor()
+ ** and return a Component that does the job. It is the component's job,
+ ** or the PropertyEditor's job, to make sure that when the editor changes
+ ** its value, the PropertyChangeEvent is thrown.</LI>
+ ** </OL>
+ **
+ ** The PropertyEditor for a particular Bean can be found using the
+ ** PropertyEditorManager class, which goes through a series of different
+ ** checks to find the appropriate class.<P>
+ **
+ ** A PropertyChangeEvent should be thrown from the PropertyEditor whenever a
+ ** bound property (a property PropertyDescriptor.isBound() set to true)
+ ** changes. When this happens, the editor itself should *not* change the value
+ ** itself, but rather allow the RAD tool to call setValue() or setAsText().
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 30 June 1998
+ ** @see java.beans.PropertyEditorManager
+ ** @see java.beans.PropertyEditorSupport
+ **/
+
+public interface PropertyEditor {
+ /** Called by the RAD tool to set the value of this property for the PropertyEditor.
+ ** If the property type is native, it should be wrapped in the appropriate
+ ** wrapper type.
+ ** @param value the value to set this property to.
+ **/
+ void setValue(Object value);
+
+ /** Accessor method to get the current value the PropertyEditor is working with.
+ ** If the property type is native, it will be wrapped in the appropriate
+ ** wrapper type.
+ ** @return the current value of the PropertyEditor.
+ **/
+ Object getValue();
+
+
+ /** Set the value of this property using a String.
+ ** Whether or not this PropertyEditor is editing a String type, this converts
+ ** the String into the type of the PropertyEditor.
+ ** @param text the text to set it to.
+ ** @exception IllegalArgumentException if the String is in the wrong format or setAsText() is not supported.
+ **/
+ void setAsText(String text) throws IllegalArgumentException;
+
+ /** Get the value of this property in String format.
+ ** Many times this can simply use Object.toString().<P>
+ ** Return null if you do not support getAsText()/setAsText().
+ ** <code>setAsText(getAsText())</code> should be valid; i.e. the stuff you spit out in
+ ** getAsText() should be able to go into setAsText().
+ ** @return the value of this property in String format.
+ **/
+ String getAsText();
+
+ /** Get a list of possible Strings which this property type can have.
+ ** The value of these will be used by the RAD tool to construct some sort
+ ** of list box or to check text box input, and the resulting String passed
+ ** to setAsText() should be one of these. Note, however, that like most things
+ ** with this mammoth, unwieldy interface, this is not guaranteed. Thus, you
+ ** must check the value in setAsText() anyway.
+ ** @return the list of possible String values for this property type.
+ **/
+ String[] getTags();
+
+
+ /** The RAD tool calls this to find out whether the PropertyEditor can paint itself.
+ ** @return true if it can paint itself graphically, false if it cannot.
+ **/
+ boolean isPaintable();
+
+ /** The RAD tool calls this to paint the actual value of the property.
+ ** The Graphics context will have the same current font, color, etc. as the
+ ** parent Container. You may safely change the font, color, etc. and not
+ ** change them back.<P>
+ ** This method should do a silent no-op if isPaintable() is false.
+ ** @param g the Graphics context to paint on
+ ** @param bounds the rectangle you have reserved to work in
+ **/
+ void paintValue(java.awt.Graphics g, java.awt.Rectangle bounds);
+
+
+ /** The RAD tool calls this to find out whether the PropertyEditor supports a custom component to edit and display itself.
+ ** @return true if getCustomEditor() will return a component, false if not.
+ **/
+ boolean supportsCustomEditor();
+
+ /** The RAD tool calls this to grab the component that can edit this type.
+ ** The component may be painted anywhere the RAD tool wants to paint it--
+ ** even in its own window.<P>
+ ** The component must hook up with the PropertyEditor and, whenever a
+ ** change to the value is made, fire a PropertyChangeEvent to the source.<P>
+ ** @return the custom editor for this property type.
+ **/
+ java.awt.Component getCustomEditor();
+
+
+ /** Adds a property change listener to this PropertyEditor.
+ ** @param listener the listener to add
+ **/
+ void addPropertyChangeListener(PropertyChangeListener listener);
+
+ /** Removes a property change listener from this PropertyEditor.
+ ** @param listener the listener to remove
+ **/
+ void removePropertyChangeListener(PropertyChangeListener listener);
+
+ /** Get a Java language-specific String which could be used to create an Object
+ ** of the specified type. Every PropertyEditor must support this.<P>
+ ** The reason for this is that while most RAD tools will serialize the Beans
+ ** and deserialize them at runtime, some RAD tools will generate code that
+ ** creates the Beans. Examples of Java initialization strings would be:<P>
+ ** <OL>
+ ** <LI><CODE>2</CODE></LI>
+ ** <LI><CODE>"I am a String"</CODE></LI>
+ ** <LI><CODE>new MyObject(2, "String", new StringBuffer())</CODE></LI>
+ ** </OL>
+ ** @return the initialization string for this object in Java.
+ **/
+ String getJavaInitializationString();
+}
diff --git a/libjava/classpath/java/beans/PropertyEditorManager.java b/libjava/classpath/java/beans/PropertyEditorManager.java
new file mode 100644
index 000000000..253ddafe1
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyEditorManager.java
@@ -0,0 +1,216 @@
+/* java.beans.PropertyEditorManager
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.beans.editors.ColorEditor;
+import gnu.java.beans.editors.FontEditor;
+import gnu.java.beans.editors.NativeBooleanEditor;
+import gnu.java.beans.editors.NativeByteEditor;
+import gnu.java.beans.editors.NativeDoubleEditor;
+import gnu.java.beans.editors.NativeFloatEditor;
+import gnu.java.beans.editors.NativeIntEditor;
+import gnu.java.beans.editors.NativeLongEditor;
+import gnu.java.beans.editors.NativeShortEditor;
+import gnu.java.beans.editors.StringEditor;
+import gnu.java.lang.ClassHelper;
+
+import java.awt.Color;
+import java.awt.Font;
+
+/**
+ * PropertyEditorManager is used to find property editors
+ * for various types (not necessarily Beans).<P>
+ *
+ * It first checks to see if the property editor is
+ * already registered; if it is, that property editor is
+ * used. Next it takes the type's classname and appends
+ * "Editor" to it, and searches first in the class's
+ * package and then in the property editor search path.
+ *
+ * <p>Default property editors are provided for:</p>
+ *
+ * <ol>
+ * <li>boolean, byte, short, int, long, float, and double</li>
+ * <li>java.lang.String</li>
+ * <li>java.awt.Color</li>
+ * <li>java.awt.Font</li>
+ * </ol>
+ *
+ * <p><strong>Spec Suggestion:</strong> Perhaps an editor for
+ * Filename or something like it should be provided. As well
+ * as char.</p>
+ *
+ * @author John Keiser
+ * @since 1.1
+ * @version 1.1.0, 29 Jul 1998
+ */
+
+public class PropertyEditorManager
+{
+ static java.util.Hashtable<Class<?>,Class<?>> editors =
+ new java.util.Hashtable<Class<?>,Class<?>>();
+ static String[] editorSearchPath = { "gnu.java.beans.editors",
+ "sun.beans.editors" };
+
+ static
+ {
+ registerEditor(Boolean.TYPE, NativeBooleanEditor.class);
+ registerEditor(Byte.TYPE, NativeByteEditor.class);
+ registerEditor(Short.TYPE, NativeShortEditor.class);
+ registerEditor(Integer.TYPE, NativeIntEditor.class);
+ registerEditor(Long.TYPE, NativeLongEditor.class);
+ registerEditor(Float.TYPE, NativeFloatEditor.class);
+ registerEditor(Double.TYPE, NativeDoubleEditor.class);
+ registerEditor(String.class, StringEditor.class);
+ registerEditor(Color.class, ColorEditor.class);
+ registerEditor(Font.class, FontEditor.class);
+ }
+
+ /**
+ * Beats me why this class can be instantiated, but there
+ * you have it.
+ */
+ public PropertyEditorManager()
+ {
+ // Do nothing here
+ }
+
+ /**
+ * Register an editor for a class. Replaces old editor
+ * if there was one registered before.
+ *
+ * @param editedClass the class that the property editor
+ * will edit.
+ * @param editorClass the PropertyEditor class.
+ */
+ public static void registerEditor(Class<?> editedClass, Class<?> editorClass)
+ {
+ editors.put(editedClass, editorClass);
+ }
+
+ /**
+ * Returns a new instance of the property editor for the
+ * specified class.
+ *
+ * @param editedClass the class that the property editor
+ * will edit.
+ * @return a PropertyEditor instance that can edit the
+ * specified class.
+ */
+ public static PropertyEditor findEditor(Class<?> editedClass)
+ {
+ try
+ {
+ Class found = (Class)editors.get(editedClass);
+ if(found != null)
+ {
+ return (PropertyEditor)found.newInstance();
+ }
+
+ ClassLoader contextClassLoader
+ = Thread.currentThread().getContextClassLoader();
+
+ try
+ {
+ found = Class.forName(editedClass.getName()+"Editor", true,
+ contextClassLoader);
+ registerEditor(editedClass,found);
+ return (PropertyEditor)found.newInstance();
+ }
+ catch(ClassNotFoundException E)
+ {
+ }
+
+ String appendName
+ = "."
+ + ClassHelper.getTruncatedClassName(editedClass)
+ + "Editor";
+ synchronized(editorSearchPath)
+ {
+ for(int i=0;i<editorSearchPath.length;i++)
+ {
+ try
+ {
+ found = Class.forName(editorSearchPath[i] + appendName,
+ true, contextClassLoader);
+ registerEditor(editedClass,found);
+ return (PropertyEditor)found.newInstance();
+ }
+ catch(ClassNotFoundException E)
+ {
+ }
+ }
+ }
+ }
+ catch(InstantiationException E)
+ {
+ }
+ catch(IllegalAccessException E)
+ {
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the editor search path.
+ * As a minor departure from the spec, the default value
+ * for the editor search path is "gnu.java.beans.editors",
+ * "sun.beans.editors".
+ *
+ * @return the editor search path.
+ */
+ public static String[] getEditorSearchPath()
+ {
+ return editorSearchPath;
+ }
+
+ /**
+ * Set the editor search path.
+ *
+ * @param editorSearchPath the new value for the editor search path.
+ */
+ public static void setEditorSearchPath(String[] editorSearchPath)
+ {
+ synchronized(editorSearchPath)
+ {
+ PropertyEditorManager.editorSearchPath = editorSearchPath;
+ }
+ }
+}
diff --git a/libjava/classpath/java/beans/PropertyEditorSupport.java b/libjava/classpath/java/beans/PropertyEditorSupport.java
new file mode 100644
index 000000000..bb68e0e31
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyEditorSupport.java
@@ -0,0 +1,265 @@
+/* java.beans.PropertyEditorSupport
+ Copyright (C) 1998, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+
+/**
+ * PropertyEditorSupport helps with PropertyEditors,
+ * implementing base functionality that they usually must
+ * have but which is a pain to implement. You may extend
+ * from this class or use it as a standalone.<P>
+ *
+ * This class does not do any painting or actual editing.
+ * For that, you must use or extend it. See the
+ * PropertyEditor class for better descriptions of what
+ * the various methods do.
+ *
+ * @author John Keiser
+ * @author Robert Schuster
+ * @since 1.1
+ * @status updated to 1.5
+ */
+public class PropertyEditorSupport implements PropertyEditor
+{
+ Object eventSource;
+ Object value;
+ PropertyChangeSupport pSupport;
+
+ /** Call this constructor when you are deriving from
+ * PropertyEditorSupport.
+ *
+ * Using this constructor the event source is this PropertyEditorSupport
+ * instance itself.
+ *
+ * @since 1.5
+ * @specnote this was <code>protected</code> prior to 1.5
+ */
+ public PropertyEditorSupport()
+ {
+ eventSource = this;
+ pSupport = new PropertyChangeSupport(this);
+ }
+
+ /** Call this constructor when you are using
+ * PropertyEditorSupport as a helper object.
+ *
+ * This constructor throws a NullPointerException when <code>source</code> is <code>null</code>,
+ * for compatibility reasons with J2SDK 1.5.0 .
+ *
+ * @param source The source to use when firing
+ * property change events.
+ * @since 1.5
+ * @specnote this was <code>protected</code> prior to 1.5
+ */
+ public PropertyEditorSupport(Object source)
+ {
+ // note: constructor rejects source being null for the sake of compatibility
+ // with official 1.5.0 implementation
+ if (source == null)
+ throw new NullPointerException("Event source must not be null.");
+
+ eventSource = source;
+ pSupport = new PropertyChangeSupport(eventSource);
+ }
+
+ /** Sets the current value of the property and a property change
+ * event is fired to all registered PropertyChangeListener instances.
+ *
+ * @param newValue The new value for the property.
+ */
+ public void setValue(Object newValue)
+ {
+ value = newValue;
+
+ // specification in java.beans.PropertyChangeEvent says
+ // that without a property name (first argument) the
+ // new and the old value should always be null
+ pSupport.firePropertyChange(null, null, null);
+ }
+
+ /** Gets the current value of the property.
+ *
+ * @return the current value of the property.
+ */
+ public Object getValue()
+ {
+ return value;
+ }
+
+ /** Gets whether this object is paintable or not.
+ *
+ * @return <CODE>false</CODE>
+ */
+ public boolean isPaintable()
+ {
+ return false;
+ }
+
+ /** Paints this object. This class does nothing in
+ * this method.
+ */
+ public void paintValue(java.awt.Graphics g, java.awt.Rectangle r)
+ {
+ }
+
+ /** Gets the Java initialization String for the current
+ * value of the Object. This class returns gibberish or
+ * null (though the spec does not say which).<P>
+ * <STRONG>Implementation Note:</STRONG> This class
+ * returns the string "@$#^" to make sure the code will
+ * be broken, so that you will know to override it when
+ * you create your own property editor.
+ *
+ * @return the Java initialization string.
+ */
+ public String getJavaInitializationString()
+ {
+ return "@$#^";
+ }
+
+ /** Gets the value as text.
+ * In this class, you cannot count on getAsText() doing
+ * anything useful, although in this implementation I
+ * do toString().
+ *
+ * @return the value as text.
+ */
+ public String getAsText()
+ {
+ return value != null ? value.toString() : "null";
+ }
+
+ /** Sets the value as text.
+ * In this class, you cannot count on setAsText() doing
+ * anything useful across implementations.
+ * <STRONG>Implementation Note:</STRONG> In this
+ * implementation it checks if the String is "null", and
+ * if it is, sets the value to null, otherwise it throws
+ * an IllegalArgumentException.
+ *
+ * @param s the text to convert to a new value.
+ * @exception IllegalArgumentException if the text is
+ * malformed.
+ */
+ public void setAsText(String s) throws IllegalArgumentException
+ {
+ if (s.equals("null"))
+ setValue(null);
+ else
+ throw new IllegalArgumentException();
+ }
+
+ /** Returns a list of possible choices for the value.
+ *
+ * @return <CODE>null</CODE>
+ */
+ public String[] getTags()
+ {
+ return null;
+ }
+
+ /** Returns a custom component to edit the value.
+ *
+ * @return <CODE>null</CODE> in this class.
+ */
+ public java.awt.Component getCustomEditor()
+ {
+ return null;
+ }
+
+ /** Finds out whether this property editor supports a
+ * custom component to edit its value.
+ *
+ * @return <CODE>false</CODE> in this class.
+ */
+ public boolean supportsCustomEditor()
+ {
+ return false;
+ }
+
+ /** Adds a property change listener to this property editor.
+ *
+ * @param l the listener to add.
+ */
+ public void addPropertyChangeListener(PropertyChangeListener l)
+ {
+ pSupport.addPropertyChangeListener(l);
+ }
+
+ /** Removes a property change listener from this property editor.
+ *
+ * @param l the listener to remove.
+ */
+ public void removePropertyChangeListener(PropertyChangeListener l)
+ {
+ pSupport.removePropertyChangeListener(l);
+ }
+
+ /** Notifies people that we've changed, although we don't
+ * tell them just how.
+ */
+ public void firePropertyChange()
+ {
+ pSupport.firePropertyChange(null, null, null);
+ }
+
+ /** Returns the bean that is used as the source of events.
+ *
+ * @return The event source object
+ * @since 1.5
+ */
+ public Object getSource()
+ {
+ return eventSource;
+ }
+
+ /** Sets the bean that is used as the source of events
+ * when property changes occur.
+ *
+ * The event source bean is for informational purposes only
+ * and should not be changed by the <code>PropertyEditor</code>.
+ *
+ * @param source
+ * @since 1.5
+ */
+ public void setSource(Object source)
+ {
+ eventSource = source;
+ }
+}
diff --git a/libjava/classpath/java/beans/PropertyVetoException.java b/libjava/classpath/java/beans/PropertyVetoException.java
new file mode 100644
index 000000000..1f0399b4b
--- /dev/null
+++ b/libjava/classpath/java/beans/PropertyVetoException.java
@@ -0,0 +1,85 @@
+/* PropertyVetoException.java -- thrown to veto a proposed property change
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * PropertyVetoException is thrown when a VetoableChangeListener doesn't
+ * like the proposed change.
+ *
+ * @author John Keiser
+ * @see VetoableChangeListener
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class PropertyVetoException extends Exception
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 129596057694162164L;
+
+ /**
+ * The vetoed change.
+ *
+ * @serial the event that was vetoed
+ */
+ private final PropertyChangeEvent evt;
+
+ /**
+ * Instantiate this exception with the given message and property change.
+ *
+ * @param msg the reason for the veto
+ * @param changeEvent the PropertyChangeEvent that was thrown
+ */
+ public PropertyVetoException(String msg, PropertyChangeEvent changeEvent)
+ {
+ super(msg);
+ evt = changeEvent;
+ }
+
+ /**
+ * Get the PropertyChange event that was vetoed.
+ *
+ * @return the vetoed change
+ */
+ public PropertyChangeEvent getPropertyChangeEvent()
+ {
+ return evt;
+ }
+}
diff --git a/libjava/classpath/java/beans/SimpleBeanInfo.java b/libjava/classpath/java/beans/SimpleBeanInfo.java
new file mode 100644
index 000000000..d5216caf5
--- /dev/null
+++ b/libjava/classpath/java/beans/SimpleBeanInfo.java
@@ -0,0 +1,145 @@
+/* java.beans.SimpleBeanInfo
+ Copyright (C) 1998, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+
+/**
+ ** SimpleBeanInfo is a class you may extend to more easily
+ ** provide select information to the Introspector. It
+ ** implements all of the methods in BeanInfo by returning
+ ** null and forces the Introspector to behave exactly as
+ ** if there were no BeanInfo class at all (Introspecting
+ ** everything).<P>
+ **
+ ** Overriding one or two of these functions
+ ** to give explicit information on only those things you
+ ** wish to give explicit information is perfectly safe,
+ ** and even desirable.<P>
+ **
+ ** See the BeanInfo class for information on what the
+ ** various methods actually do.
+ **
+ ** @author John Keiser
+ ** @since JDK1.1
+ ** @version 1.1.0, 29 Jul 1998
+ ** @see java.beans.BeanInfo
+ **/
+
+public class SimpleBeanInfo implements BeanInfo {
+ /** Force Introspection of the general bean info.
+ ** @return <CODE>null</CODE>.
+ **/
+ public BeanDescriptor getBeanDescriptor() {
+ return null;
+ }
+
+ /** Force Introspection of the events this Bean type
+ ** fires.
+ ** @return <CODE>null</CODE>
+ **/
+ public EventSetDescriptor[] getEventSetDescriptors() {
+ return null;
+ }
+
+ /** Say that there is no "default" event set.
+ ** @return <CODE>-1</CODE>.
+ **/
+ public int getDefaultEventIndex() {
+ return -1;
+ }
+
+ /** Force Introspection of the Bean properties.
+ ** @return <CODE>null</CODE>.
+ **/
+ public PropertyDescriptor[] getPropertyDescriptors() {
+ return null;
+ }
+
+ /** Say that there is no "default" property.
+ ** @return <CODE>-1</CODE>.
+ **/
+ public int getDefaultPropertyIndex() {
+ return -1;
+ }
+
+ /** Force Introspection of the Bean's methods.
+ ** @return <CODE>null</CODE>.
+ **/
+ public MethodDescriptor[] getMethodDescriptors() {
+ return null;
+ }
+
+ /** Tell the Introspector to go look for other BeanInfo
+ ** itself.
+ ** @return <CODE>null</CODE>.
+ **/
+ public BeanInfo[] getAdditionalBeanInfo() {
+ return null;
+ }
+
+ /** Say that this Bean has no icons.
+ ** @param iconType the type of icon
+ ** @return <CODE>null</CODE>.
+ **/
+ public Image getIcon(int iconType) {
+ return null;
+ }
+
+ /** Helper method to load an image using the Bean class
+ ** getResource() method on the BeanInfo class (using
+ ** getClass(), since you'll extend this class to get
+ ** the BeanInfo). Basically it's assumed that the Bean
+ ** and its BeanInfo are both loaded by the same
+ ** ClassLoader, generally a reasonable assumption.
+ ** @param location the URL relative
+ ** @return the Image in question (possibly <code>null</code>).
+ **/
+ public Image loadImage(String location)
+ {
+ if (location == null)
+ return null;
+ URL url = getClass().getResource(location);
+ if (url == null)
+ return null;
+ return Toolkit.getDefaultToolkit().getImage(url);
+ }
+}
diff --git a/libjava/classpath/java/beans/Statement.java b/libjava/classpath/java/beans/Statement.java
new file mode 100644
index 000000000..d9cd304da
--- /dev/null
+++ b/libjava/classpath/java/beans/Statement.java
@@ -0,0 +1,386 @@
+/* Statement.java
+ Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * <p>A Statement captures the execution of an object method. It stores
+ * the object, the method to call, and the arguments to the method and
+ * provides the ability to execute the method on the object, using the
+ * provided arguments.</p>
+ *
+ * @author Jerry Quinn (jlquinn@optonline.net)
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.4
+ */
+public class Statement
+{
+ private Object target;
+ private String methodName;
+ private Object[] arguments;
+
+ /**
+ * One or the other of these will get a value after execute is
+ * called once, but not both.
+ */
+ private transient Method method;
+ private transient Constructor ctor;
+
+ /**
+ * <p>Constructs a statement representing the invocation of
+ * object.methodName(arg[0], arg[1], ...);</p>
+ *
+ * <p>If the argument array is null it is replaced with an
+ * array of zero length.</p>
+ *
+ * @param target The object to invoke the method on.
+ * @param methodName The object method to invoke.
+ * @param arguments An array of arguments to pass to the method.
+ */
+ public Statement(Object target, String methodName, Object[] arguments)
+ {
+ this.target = target;
+ this.methodName = methodName;
+ this.arguments = (arguments != null) ? arguments : new Object[0];
+ }
+
+ /**
+ * Execute the statement.
+ *
+ * <p>Finds the specified method in the target object and calls it with
+ * the arguments given in the constructor.</p>
+ *
+ * <p>The most specific method according to the JLS(15.11) is used when
+ * there are multiple methods with the same name.</p>
+ *
+ * <p>Execute performs some special handling for methods and
+ * parameters:
+ * <ul>
+ * <li>Static methods can be executed by providing the class as a
+ * target.</li>
+ *
+ * <li>The method name new is reserved to call the constructor
+ * new() will construct an object and return it. Not useful unless
+ * an expression :-)</li>
+ *
+ * <li>If the target is an array, get and set as defined in
+ * java.util.List are recognized as valid methods and mapped to the
+ * methods of the same name in java.lang.reflect.Array.</li>
+ *
+ * <li>The native datatype wrappers Boolean, Byte, Character, Double,
+ * Float, Integer, Long, and Short will map to methods that have
+ * native datatypes as parameters, in the same way as Method.invoke.
+ * However, these wrappers also select methods that actually take
+ * the wrapper type as an argument.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>The Sun spec doesn't deal with overloading between int and
+ * Integer carefully. If there are two methods, one that takes an
+ * Integer and the other taking an int, the method chosen is not
+ * specified, and can depend on the order in which the methods are
+ * declared in the source file.</p>
+ *
+ * @throws Exception if an exception occurs while locating or
+ * invoking the method.
+ */
+ public void execute() throws Exception
+ {
+ doExecute();
+ }
+
+ private static Class wrappers[] =
+ {
+ Boolean.class, Byte.class, Character.class, Double.class, Float.class,
+ Integer.class, Long.class, Short.class
+ };
+
+ private static Class natives[] =
+ {
+ Boolean.TYPE, Byte.TYPE, Character.TYPE, Double.TYPE, Float.TYPE,
+ Integer.TYPE, Long.TYPE, Short.TYPE
+ };
+
+ /** Given a wrapper class, return the native class for it.
+ * <p>For example, if <code>c</code> is <code>Integer</code>,
+ * <code>Integer.TYPE</code> is returned.</p>
+ */
+ private Class unwrap(Class c)
+ {
+ for (int i = 0; i < wrappers.length; i++)
+ if (c == wrappers[i])
+ return natives[i];
+ return null;
+ }
+
+ /** Returns <code>true</code> if all args can be assigned to
+ * <code>params</code>, <code>false</code> otherwise.
+ *
+ * <p>Arrays are guaranteed to be the same length.</p>
+ */
+ private boolean compatible(Class[] params, Class[] args)
+ {
+ for (int i = 0; i < params.length; i++)
+ {
+ // Argument types are derived from argument values. If one of them was
+ // null then we cannot deduce its type. However null can be assigned to
+ // any type.
+ if (args[i] == null)
+ continue;
+
+ // Treat Integer like int if appropriate
+ Class nativeType = unwrap(args[i]);
+ if (nativeType != null && params[i].isPrimitive()
+ && params[i].isAssignableFrom(nativeType))
+ continue;
+ if (params[i].isAssignableFrom(args[i]))
+ continue;
+
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns <code>true</code> if the method arguments in first are
+ * more specific than the method arguments in second, i.e. all
+ * arguments in <code>first</code> can be assigned to those in
+ * <code>second</code>.
+ *
+ * <p>A method is more specific if all parameters can also be fed to
+ * the less specific method, because, e.g. the less specific method
+ * accepts a base class of the equivalent argument for the more
+ * specific one.</p>
+ *
+ * @param first a <code>Class[]</code> value
+ * @param second a <code>Class[]</code> value
+ * @return a <code>boolean</code> value
+ */
+ private boolean moreSpecific(Class[] first, Class[] second)
+ {
+ for (int j=0; j < first.length; j++)
+ {
+ if (second[j].isAssignableFrom(first[j]))
+ continue;
+ return false;
+ }
+ return true;
+ }
+
+ final Object doExecute() throws Exception
+ {
+ Class klazz = (target instanceof Class)
+ ? (Class) target : target.getClass();
+ Object args[] = (arguments == null) ? new Object[0] : arguments;
+ Class argTypes[] = new Class[args.length];
+
+ // Retrieve type or use null if the argument is null. The null argument
+ // type is later used in compatible().
+ for (int i = 0; i < args.length; i++)
+ argTypes[i] = (args[i] != null) ? args[i].getClass() : null;
+
+ if (target.getClass().isArray())
+ {
+ // FIXME: invoke may have to be used. For now, cast to Number
+ // and hope for the best. If caller didn't behave, we go boom
+ // and throw the exception.
+ if (methodName.equals("get") && argTypes.length == 1)
+ return Array.get(target, ((Number)args[0]).intValue());
+ if (methodName.equals("set") && argTypes.length == 2)
+ {
+ Object obj = Array.get(target, ((Number)args[0]).intValue());
+ Array.set(target, ((Number)args[0]).intValue(), args[1]);
+ return obj;
+ }
+ throw new NoSuchMethodException("No matching method for statement " + toString());
+ }
+
+ // If we already cached the method, just use it.
+ if (method != null)
+ return method.invoke(target, args);
+ else if (ctor != null)
+ return ctor.newInstance(args);
+
+ // Find a matching method to call. JDK seems to go through all
+ // this to find the method to call.
+
+ // if method name or length don't match, skip
+ // Need to go through each arg
+ // If arg is wrapper - check if method arg is matchable builtin
+ // or same type or super
+ // - check that method arg is same or super
+
+ if (methodName.equals("new") && target instanceof Class)
+ {
+ Constructor ctors[] = klazz.getConstructors();
+ for (int i = 0; i < ctors.length; i++)
+ {
+ // Skip methods with wrong number of args.
+ Class ptypes[] = ctors[i].getParameterTypes();
+
+ if (ptypes.length != args.length)
+ continue;
+
+ // Check if method matches
+ if (!compatible(ptypes, argTypes))
+ continue;
+
+ // Use method[i] if it is more specific.
+ // FIXME: should this check both directions and throw if
+ // neither is more specific?
+ if (ctor == null)
+ {
+ ctor = ctors[i];
+ continue;
+ }
+ Class mptypes[] = ctor.getParameterTypes();
+ if (moreSpecific(ptypes, mptypes))
+ ctor = ctors[i];
+ }
+ if (ctor == null)
+ throw new InstantiationException("No matching constructor for statement " + toString());
+ return ctor.newInstance(args);
+ }
+
+ Method methods[] = klazz.getMethods();
+
+ for (int i = 0; i < methods.length; i++)
+ {
+ // Skip methods with wrong name or number of args.
+ if (!methods[i].getName().equals(methodName))
+ continue;
+ Class ptypes[] = methods[i].getParameterTypes();
+ if (ptypes.length != args.length)
+ continue;
+
+ // Check if method matches
+ if (!compatible(ptypes, argTypes))
+ continue;
+
+ // Use method[i] if it is more specific.
+ // FIXME: should this check both directions and throw if
+ // neither is more specific?
+ if (method == null)
+ {
+ method = methods[i];
+ continue;
+ }
+ Class mptypes[] = method.getParameterTypes();
+ if (moreSpecific(ptypes, mptypes))
+ method = methods[i];
+ }
+ if (method == null)
+ throw new NoSuchMethodException("No matching method for statement " + toString());
+
+ // If we were calling Class.forName(String) we intercept and call the
+ // forName-variant that allows a ClassLoader argument. We take the
+ // system classloader (aka application classloader) here to make sure
+ // that application defined classes can be resolved. If we would not
+ // do that the Class.forName implementation would use the class loader
+ // of java.beans.Statement which is <null> and cannot resolve application
+ // defined classes.
+ if (method.equals(
+ Class.class.getMethod("forName", new Class[] { String.class })))
+ return Class.forName(
+ (String) args[0], true, ClassLoader.getSystemClassLoader());
+
+ try {
+ return method.invoke(target, args);
+ } catch(IllegalArgumentException iae){
+ System.err.println("method: " + method);
+
+ for(int i=0;i<args.length;i++){
+ System.err.println("args[" + i + "]: " + args[i]);
+ }
+ throw iae;
+ }
+ }
+
+
+
+ /** Return the statement arguments. */
+ public Object[] getArguments() { return arguments; }
+
+ /** Return the statement method name. */
+ public String getMethodName() { return methodName; }
+
+ /** Return the statement object. */
+ public Object getTarget() { return target; }
+
+ /**
+ * Returns a string representation of this <code>Statement</code>.
+ *
+ * @return A string representation of this <code>Statement</code>.
+ */
+ public String toString()
+ {
+ CPStringBuilder result = new CPStringBuilder();
+
+ String targetName;
+ if (target != null)
+ targetName = target.getClass().getSimpleName();
+ else
+ targetName = "null";
+
+ result.append(targetName);
+ result.append(".");
+ result.append(methodName);
+ result.append("(");
+
+ String sep = "";
+ for (int i = 0; i < arguments.length; i++)
+ {
+ result.append(sep);
+ result.append(
+ ( arguments[i] == null ) ? "null" :
+ ( arguments[i] instanceof String ) ? "\"" + arguments[i] + "\"" :
+ arguments[i].getClass().getSimpleName());
+ sep = ", ";
+ }
+ result.append(");");
+
+ return result.toString();
+ }
+
+}
diff --git a/libjava/classpath/java/beans/TODO b/libjava/classpath/java/beans/TODO
new file mode 100644
index 000000000..08e1d25ee
--- /dev/null
+++ b/libjava/classpath/java/beans/TODO
@@ -0,0 +1,4 @@
+- add AppletStub and AppletContext to java.beans.Beans.instantiate().
+- make Introspector more efficient.
+- basic Introspection tests are in, but more tests are probably in order.
+- 1.2 support (waiting on java.lang.Package, mainly)
diff --git a/libjava/classpath/java/beans/VetoableChangeListener.java b/libjava/classpath/java/beans/VetoableChangeListener.java
new file mode 100644
index 000000000..5107954b0
--- /dev/null
+++ b/libjava/classpath/java/beans/VetoableChangeListener.java
@@ -0,0 +1,73 @@
+/* VetoableChangeListener.java -- listen for a change which can be vetoed
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventListener;
+
+/**
+ * VetoableChangeListener allows a class to monitor proposed changes to
+ * properties of a Bean and, if desired, prevent them from occurring. A
+ * vetoableChange() event will be fired <em>after</em> the property change has
+ * been requested, but before it is permanent. If any listener rejects the
+ * change by throwing the PropertyChangeException, a new vetoableChange()
+ * event will be fired to all listeners who received a vetoableChange() event
+ * in the first place, informing them to revert back to the old value. Thus,
+ * the listener that threw the exception the first time should be prepared
+ * to rethrow it the second time. The value, of course, never actually changed.
+ *
+ * <p><strong>Note:</strong> This class may not be reliably used to determine
+ * whether a property has actually changed. Use the PropertyChangeListener
+ * interface for that instead.
+ *
+ * @author John Keiser
+ * @see java.beans.PropertyChangeListener
+ * @see java.beans.VetoableChangeSupport
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public interface VetoableChangeListener extends EventListener
+{
+ /**
+ * Fired before a Bean's property changes.
+ *
+ * @param e the change (containing the old and new values)
+ * @throws PropertyVetoException if the change is vetoed by the listener
+ */
+ void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException;
+} // interface VetoableChangeListener
diff --git a/libjava/classpath/java/beans/VetoableChangeListenerProxy.java b/libjava/classpath/java/beans/VetoableChangeListenerProxy.java
new file mode 100644
index 000000000..56ca5a38c
--- /dev/null
+++ b/libjava/classpath/java/beans/VetoableChangeListenerProxy.java
@@ -0,0 +1,102 @@
+/* VetoableChangeListenerProxy.java -- adds a name to a vetoable listener
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * This class provides an extension to <code>VetoableChangeListener</code> -
+ * associating a name with the listener. This can be used to filter the
+ * changes that one is interested in.
+ *
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.4
+ * @status udpated to 1.4
+ */
+public class VetoableChangeListenerProxy extends EventListenerProxy
+ implements VetoableChangeListener
+{
+ /**
+ * The name of the property to listen for. Package visible for use by
+ * VetoableChangeSupport.
+ */
+ final String propertyName;
+
+ /**
+ * Create a new proxy which filters property change events and only passes
+ * changes to the named property on to the delegate.
+ *
+ * @param propertyName the property's name to filter on
+ * @param listener the delegate listener
+ */
+ public VetoableChangeListenerProxy(String propertyName,
+ VetoableChangeListener listener)
+ {
+ super(listener);
+ this.propertyName = propertyName;
+ }
+
+ /**
+ * Forwards the event on to the delegate if the property name matches.
+ *
+ * @param event the event to pass on, if it meets the filter
+ * @throws NullPointerException if the delegate this was created with is null
+ * @throws PropertyVetoException if the change is vetoed by the listener
+ */
+ public void vetoableChange(PropertyChangeEvent event)
+ throws PropertyVetoException
+ {
+ // Note: Sun does not filter, under the assumption that since
+ // VetoableChangeSupport unwraps proxys, this method should never be
+ // called by normal use of listeners.
+ String name = event == null ? null : event.getPropertyName();
+ if (name == null ? propertyName == null : name.equals(propertyName))
+ ((VetoableChangeListener) getListener()).vetoableChange(event);
+ }
+
+ /**
+ * Gets the name of the property this proxy is filtering on.
+ *
+ * @return the property name
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+} // class VetoableChangeListenerProxy
diff --git a/libjava/classpath/java/beans/VetoableChangeSupport.java b/libjava/classpath/java/beans/VetoableChangeSupport.java
new file mode 100644
index 000000000..698e82d8f
--- /dev/null
+++ b/libjava/classpath/java/beans/VetoableChangeSupport.java
@@ -0,0 +1,532 @@
+/* VetoableChangeSupport.java -- support to manage vetoable change listeners
+ Copyright (C) 1998, 1999, 2000, 2002, 2005, 2006,
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+/**
+ * VetoableChangeSupport makes it easy to fire vetoable change events and
+ * handle listeners. It allows chaining of listeners, as well as filtering
+ * by property name. In addition, it will serialize only those listeners
+ * which are serializable, ignoring the others without problem. This class
+ * is thread-safe.
+ *
+ * @author John Keiser
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class VetoableChangeSupport implements Serializable
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -5090210921595982017L;
+
+ /**
+ * Maps property names (String) to named listeners (VetoableChangeSupport).
+ * If this is a child instance, this field will be null.
+ *
+ * @serial the map of property names to named listener managers
+ * @since 1.2
+ */
+ private Hashtable children;
+
+ /**
+ * The non-null source object for any generated events.
+ *
+ * @serial the event source
+ */
+ private final Object source;
+
+ /**
+ * A field to compare serialization versions - this class uses version 2.
+ *
+ * @serial the serialization format
+ */
+ private static final int vetoableChangeSupportSerializedDataVersion = 2;
+
+ /**
+ * The list of all registered vetoable listeners. If this instance was
+ * created by user code, this only holds the global listeners (ie. not tied
+ * to a name), and may be null. If it was created by this class, as a
+ * helper for named properties, then this vector will be non-null, and this
+ * instance appears as a value in the <code>children</code> hashtable of
+ * another instance, so that the listeners are tied to the key of that
+ * hashtable entry.
+ */
+ private transient Vector listeners;
+
+ /**
+ * Create a VetoableChangeSupport to work with a specific source bean.
+ *
+ * @param source the source bean to use
+ * @throws NullPointerException if source is null
+ */
+ public VetoableChangeSupport(Object source)
+ {
+ this.source = source;
+ if (source == null)
+ throw new NullPointerException();
+ }
+
+ /**
+ * Adds a VetoableChangeListener to the list of global listeners. All
+ * vetoable change events will be sent to this listener. The listener add
+ * is not unique: that is, <em>n</em> adds with the same listener will
+ * result in <em>n</em> events being sent to that listener for every
+ * vetoable change. This method will unwrap a VetoableChangeListenerProxy,
+ * registering the underlying delegate to the named property list.
+ *
+ * @param l the listener to add (<code>null</code> ignored).
+ */
+ public synchronized void addVetoableChangeListener(VetoableChangeListener l)
+ {
+ if (l == null)
+ return;
+ if (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ addVetoableChangeListener(p.propertyName,
+ (VetoableChangeListener) p.getListener());
+ }
+ else
+ {
+ if (listeners == null)
+ listeners = new Vector();
+ listeners.add(l);
+ }
+ }
+
+ /**
+ * Removes a VetoableChangeListener from the list of global listeners. If
+ * any specific properties are being listened on, they must be deregistered
+ * by themselves; this will only remove the general listener to all
+ * properties. If <code>add()</code> has been called multiple times for a
+ * particular listener, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * VetoableChangeListenerProxy, removing the underlying delegate from the
+ * named property list.
+ *
+ * @param l the listener to remove
+ */
+ public synchronized void
+ removeVetoableChangeListener(VetoableChangeListener l)
+ {
+ if (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ removeVetoableChangeListener(p.propertyName,
+ (VetoableChangeListener) p.getListener());
+ }
+ else if (listeners != null)
+ {
+ listeners.remove(l);
+ if (listeners.isEmpty())
+ listeners = null;
+ }
+ }
+
+ /**
+ * Returns an array of all registered vetoable change listeners. Those that
+ * were registered under a name will be wrapped in a
+ * <code>VetoableChangeListenerProxy</code>, so you must check whether the
+ * listener is an instance of the proxy class in order to see what name the
+ * real listener is registered under. If there are no registered listeners,
+ * this returns an empty array.
+ *
+ * @return the array of registered listeners
+ * @see VetoableChangeListenerProxy
+ * @since 1.4
+ */
+ public synchronized VetoableChangeListener[] getVetoableChangeListeners()
+ {
+ ArrayList list = new ArrayList();
+ if (listeners != null)
+ list.addAll(listeners);
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ Vector v = ((VetoableChangeSupport) e.getValue()).listeners;
+ int j = v.size();
+ while (--j >= 0)
+ list.add(new VetoableChangeListenerProxy
+ (name, (VetoableChangeListener) v.get(j)));
+ }
+ }
+ return (VetoableChangeListener[])
+ list.toArray(new VetoableChangeListener[list.size()]);
+ }
+
+ /**
+ * Adds a VetoableChangeListener listening on the specified property. Events
+ * will be sent to the listener only if the property name matches. The
+ * listener add is not unique; that is, <em>n</em> adds on a particular
+ * property for a particular listener will result in <em>n</em> events
+ * being sent to that listener when that property is changed. The effect is
+ * cumulative, too; if you are registered to listen to receive events on
+ * all vetoable changes, and then you register on a particular property,
+ * you will receive change events for that property twice. This method
+ * will unwrap a VetoableChangeListenerProxy, registering the underlying
+ * delegate to the named property list if the names match, and discarding
+ * it otherwise.
+ *
+ * @param propertyName the name of the property to listen on
+ * @param l the listener to add
+ */
+ public synchronized void addVetoableChangeListener(String propertyName,
+ VetoableChangeListener l)
+ {
+ if (propertyName == null || l == null)
+ return;
+ while (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (VetoableChangeListener) p.getListener();
+ }
+ VetoableChangeSupport s = null;
+ if (children == null)
+ children = new Hashtable();
+ else
+ s = (VetoableChangeSupport) children.get(propertyName);
+ if (s == null)
+ {
+ s = new VetoableChangeSupport(source);
+ s.listeners = new Vector();
+ children.put(propertyName, s);
+ }
+ s.listeners.add(l);
+ }
+
+ /**
+ * Removes a VetoableChangeListener from listening to a specific property.
+ * If <code>add()</code> has been called multiple times for a particular
+ * listener on a property, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * VetoableChangeListenerProxy, removing the underlying delegate from the
+ * named property list if the names match.
+ *
+ * @param propertyName the property to stop listening on
+ * @param l the listener to remove
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void
+ removeVetoableChangeListener(String propertyName, VetoableChangeListener l)
+ {
+ if (children == null)
+ return;
+ VetoableChangeSupport s
+ = (VetoableChangeSupport) children.get(propertyName);
+ if (s == null)
+ return;
+ while (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (VetoableChangeListener) p.getListener();
+ }
+ s.listeners.remove(l);
+ if (s.listeners.isEmpty())
+ {
+ children.remove(propertyName);
+ if (children.isEmpty())
+ children = null;
+ }
+ }
+
+ /**
+ * Returns an array of all vetoable change listeners registered under the
+ * given property name. If there are no registered listeners, this returns
+ * an empty array.
+ *
+ * @return the array of registered listeners
+ * @throws NullPointerException if propertyName is null
+ * @since 1.4
+ */
+ public synchronized VetoableChangeListener[]
+ getVetoableChangeListeners(String propertyName)
+ {
+ if (children == null)
+ return new VetoableChangeListener[0];
+ VetoableChangeSupport s
+ = (VetoableChangeSupport) children.get(propertyName);
+ if (s == null)
+ return new VetoableChangeListener[0];
+ return (VetoableChangeListener[])
+ s.listeners.toArray(new VetoableChangeListener[s.listeners.size()]);
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are non-null
+ * and equal. If the change is vetoed, a new event is fired to notify
+ * listeners about the rollback before the exception is thrown.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(String propertyName,
+ Object oldVal, Object newVal)
+ throws PropertyVetoException
+ {
+ fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+ oldVal, newVal));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ * If the change is vetoed, a new event is fired to notify listeners about
+ * the rollback before the exception is thrown.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(String propertyName, int oldVal, int newVal)
+ throws PropertyVetoException
+ {
+ if (oldVal != newVal)
+ fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+ Integer.valueOf(oldVal),
+ Integer.valueOf(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ * If the change is vetoed, a new event is fired to notify listeners about
+ * the rollback before the exception is thrown.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(String propertyName,
+ boolean oldVal, boolean newVal)
+ throws PropertyVetoException
+ {
+ if (oldVal != newVal)
+ fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+ Boolean.valueOf(oldVal),
+ Boolean.valueOf(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent to all the global listeners, and to all the
+ * listeners for the specified property name. This does nothing if old and
+ * new values of the event are equal. If the change is vetoed, a new event
+ * is fired to notify listeners about the rollback before the exception is
+ * thrown.
+ *
+ * @param event the event to fire
+ * @throws NullPointerException if event is null
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(PropertyChangeEvent event)
+ throws PropertyVetoException
+ {
+ if (event.oldValue != null && event.oldValue.equals(event.newValue))
+ return;
+ Vector v = listeners; // Be thread-safe.
+ if (v != null)
+ {
+ int i = v.size();
+ try
+ {
+ while (--i >= 0)
+ ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+ }
+ catch (PropertyVetoException e)
+ {
+ event = event.rollback();
+ int limit = i;
+ i = v.size();
+ while (--i >= limit)
+ ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+ throw e;
+ }
+ }
+ Hashtable h = children; // Be thread-safe.
+ if (h != null && event.propertyName != null)
+ {
+ VetoableChangeSupport s
+ = (VetoableChangeSupport) h.get(event.propertyName);
+ if (s != null)
+ {
+ Vector v1 = s.listeners; // Be thread-safe.
+ int i = v1 == null ? 0 : v1.size();
+ try
+ {
+ while (--i >= 0)
+ ((VetoableChangeListener) v1.get(i)).vetoableChange(event);
+ }
+ catch (PropertyVetoException e)
+ {
+ event = event.rollback();
+ int limit = i;
+ i = v.size();
+ while (--i >= 0)
+ ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+ i = v1.size();
+ while (--i >= limit)
+ ((VetoableChangeListener) v1.get(i)).vetoableChange(event);
+ throw e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Tell whether the specified property is being listened on or not. This
+ * will only return <code>true</code> if there are listeners on all
+ * properties or if there is a listener specifically on this property.
+ *
+ * @param propertyName the property that may be listened on
+ * @return whether the property is being listened on
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized boolean hasListeners(String propertyName)
+ {
+ return listeners != null || (children != null
+ && children.get(propertyName) != null);
+ }
+
+ /**
+ * Saves the state of the object to the stream.
+ *
+ * @param s the stream to write to
+ * @throws IOException if anything goes wrong
+ * @serialData this writes out a null-terminated list of serializable
+ * global vetoable change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private synchronized void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+ if (listeners != null)
+ {
+ int i = listeners.size();
+ while (--i >= 0)
+ if (listeners.get(i) instanceof Serializable)
+ s.writeObject(listeners.get(i));
+ }
+ s.writeObject(null);
+ }
+
+ /**
+ * Reads the object back from stream (deserialization).
+ *
+ * XXX Since serialization for 1.1 streams was not documented, this may
+ * not work if vetoableChangeSupportSerializedDataVersion is 1.
+ *
+ * @param s the stream to read from
+ * @throws IOException if reading the stream fails
+ * @throws ClassNotFoundException if deserialization fails
+ * @serialData this reads in a null-terminated list of serializable
+ * global vetoable change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ VetoableChangeListener l = (VetoableChangeListener) s.readObject();
+ while (l != null)
+ {
+ addVetoableChangeListener(l);
+ l = (VetoableChangeListener) s.readObject();
+ }
+ // Sun is not as careful with children as we are, and lets some proxys
+ // in that can never receive events. So, we clean up anything that got
+ // serialized, to make sure our invariants hold.
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ VetoableChangeSupport vcs = (VetoableChangeSupport) e.getValue();
+ if (vcs.listeners == null)
+ vcs.listeners = new Vector();
+ if (vcs.children != null)
+ vcs.listeners.addAll
+ (Arrays.asList(vcs.getVetoableChangeListeners(name)));
+ if (vcs.listeners.size() == 0)
+ iter.remove();
+ else
+ vcs.children = null;
+ }
+ if (children.size() == 0)
+ children = null;
+ }
+ }
+} // class VetoableChangeSupport
diff --git a/libjava/classpath/java/beans/Visibility.java b/libjava/classpath/java/beans/Visibility.java
new file mode 100644
index 000000000..338060181
--- /dev/null
+++ b/libjava/classpath/java/beans/Visibility.java
@@ -0,0 +1,85 @@
+/* java.beans.Visibility
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * Visibility is an interface a Bean may implement so that the environment
+ * can tell the Bean whether there is a GUI or not, and so that the Bean
+ * can tell the environment whether it needs one or can run without one.
+ * <P>
+ *
+ * Sun decided not to use standard Introspection patterns so that these
+ * methods did not get included when the Introspector made its sweep on
+ * the class.
+ *
+ * @author John Keiser
+ * @since JDK1.1
+ * @version 1.1.0, 29 Jul 1998
+ */
+
+public interface Visibility {
+ /**
+ * Tells whether the Bean can run without a GUI or not.
+ * @return false if Bean can run without a GUI, else true.
+ */
+ boolean needsGui();
+
+ /**
+ * Tells whether Bean is trying not to use the GUI.
+ * If needsGui() is true, this method should always return false.
+ * @return true if definitely not using GUI, otherwise false.
+ */
+ boolean avoidingGui();
+
+ /**
+ * Tells the Bean not to use GUI methods.
+ * If needsGUI() is false, then after this method is called,
+ * avoidingGui() should return true.
+ */
+ void dontUseGui();
+
+ /**
+ * Tells the Bean it may use the GUI.
+ * The Bean is not required to use the GUI in this case, it is
+ * merely being <EM>permitted</EM> to use it. If needsGui() is
+ * false, avoidingGui() may return true or false after this method
+ * is called.
+ */
+ void okToUseGui();
+}
diff --git a/libjava/classpath/java/beans/XMLDecoder.java b/libjava/classpath/java/beans/XMLDecoder.java
new file mode 100644
index 000000000..26896393a
--- /dev/null
+++ b/libjava/classpath/java/beans/XMLDecoder.java
@@ -0,0 +1,307 @@
+/* java.beans.XMLDecoder --
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.beans.DefaultExceptionListener;
+import gnu.java.beans.decoder.PersistenceParser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * The XMLDecoder reads XML data that is structured according to
+ * <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3/javabeans.dtd">this</a> DTD
+ * and creates objects according to the content. Usually such data is generated using the
+ * {@link XMLEncoder} class.
+ * <p>
+ * An example XML document might look like this:
+ * <code>
+ * &lt;java&gt;
+ * &lt;string&gt;Hello World&lt;/string&gt;
+ * &lt;int&gt;200&lt;/int&gt;
+ * &lt;/java&gt;
+ * </code>
+ * <p>To read the <code>String</code> and the <code>Integer</code> instance the following can be used (assume
+ * the XML data can be obtained from the InputStream):</p>
+ * <code>
+ * XMLDecoder decoder = new XMLDecoder(inputStreamContainingXMLData);
+ * String message = (String) decoder.readObject();
+ * Integer number = (Integer) decoder.readObject();
+ * </code>
+ * <p>Besides this basic functionality the <code>XMLDecoder</code> has some more features that might come
+ * handy in certain situations:</p>
+ * <p>An owner object can be set using the <code>setOwner</code> method which can then be accessed when
+ * decoding. This feature is only useful if the XML data is aware of the owner object. Such data may
+ * look like this (assume that the owner object is a JFrame instance):</p>
+ * <code>
+ * &lt;java&gt;
+ * &lt;void method="getOwner"&gt;
+ * &lt;void method="setVisible"&gt;
+ * &lt;boolean&gt;true&lt;boolean&gt;
+ * &lt;/void&gt;
+ * &lt;/void&gt;
+ * &lt;/java&gt;
+ * </code>
+ * This accesses the <code>JFrame</code> and makes it visible using the <code>setVisible</code> method.
+ * <p>Please note that changing the owner <b>after</b> the having read the first object has no effect,
+ * because all object have been decoded then.</p>
+ * <p>If the <code>XMLDecoder</code> is created with no {@link ExceptionListener} instance a default one
+ * is used that prints an error message to <code>System.err</code> whenever a recoverable exception
+ * is thrown. Recovarable exceptions occur when the XML data cannot be interpreted correctly (e.g
+ * unknown classes or methods, invocation on null, ...). In general be very careful when the
+ * <code>XMLDecoder</code> provoked such exceptions because the resulting object(s) may be in an
+ * undesirable state.</p>
+ * <p>Note that changing the ExceptionListener instance after <code>readObject</code> has been called
+ * once has no effect because the decoding is completed then.</p>
+ * <p>At last one can provide a specific <code>ClassLoader</code> which is then used when <code>Class</code>
+ * objects are accessed. See {@link java.lang.Class#forName(String, boolean, ClassLoader)} for details
+ * on this.</p>
+ * <p>Note: If the <code>InputStream</code> instance given to any of the constructors is <code>null</code>
+ * the resulting <code>XMLDecoder</code> will be silently (without any exception) useless. Each call
+ * to <code>readObject</code> will return <code>null</code> and never throws an
+ * <code>ArrayIndexOutOfBoundsException</code>.</p>
+ *
+ * @author Robert Schuster
+ * @since 1.4
+ * @status updated to 1.5
+ */
+public class XMLDecoder
+{
+ private Object owner;
+
+ private ExceptionListener exceptionListener;
+
+ private InputStream inputStream;
+
+ private boolean isStreamClosed;
+
+ private ClassLoader classLoader;
+
+ private Iterator iterator;
+
+ /** Creates a XMLDecoder instance that parses the XML data of the given input stream.
+ * Using this constructor no special ClassLoader, a default ExceptionListener
+ * and no owner object is used.
+ *
+ * @param in InputStream to read XML data from.
+ */
+ public XMLDecoder(InputStream in)
+ {
+ this(in, null);
+ }
+
+ /** Creates a XMLDecoder instance that parses the XML data of the given input stream.
+ * Using this constructor no special ClassLoader and a default ExceptionListener
+ * is used.
+ *
+ * @param in InputStream to read XML data from.
+ * @param owner Owner object which can be accessed and modified while parsing.
+ */
+ public XMLDecoder(InputStream in, Object owner)
+ {
+ this(in, owner, null);
+ }
+
+ /** Creates a XMLDecoder instance that parses the XML data of the given input stream.
+ * If the ExceptionListener argument is null a default implementation is used.
+ *
+ * @param in InputStream to read XML data from.
+ * @param owner Owner object which can be accessed and modified while parsing.
+ * @param exceptionListener ExceptionListener instance to which exception notifications are send.
+ */
+ public XMLDecoder(
+ InputStream in,
+ Object owner,
+ ExceptionListener exceptionListener)
+ {
+ this(
+ in,
+ owner,
+ exceptionListener,
+ Thread.currentThread().getContextClassLoader());
+ }
+
+ /** Creates a XMLDecoder instance that parses the XML data of the given input stream.
+ * If the ExceptionListener argument is null a default implementation is used.
+ *
+ * @param in InputStream to read XML data from.
+ * @param owner Owner object which can be accessed and modified while parsing.
+ * @param listener ExceptionListener instance to which exception notifications are send.
+ * @param cl ClassLoader instance that is used for calls to <code>Class.forName(String, boolean, ClassLoader)</code>
+ * @since 1.5
+ */
+ public XMLDecoder(
+ InputStream in,
+ Object owner,
+ ExceptionListener listener,
+ ClassLoader cl)
+ {
+ // initially here was a check for the validity of the InputStream argument but some
+ // great engineers decided that this API should silently discard this and behave rather
+ // odd: readObject will always return null ...
+ inputStream = in;
+
+ setExceptionListener(listener);
+
+ // validity of this object is checked in Class.forName() and therefore may be null
+ classLoader = cl;
+
+ this.owner = owner;
+ }
+
+ /** Closes the stream associated with this decoder. This should be done after having read all
+ * decoded objects.
+ * <p>See the description of the {@link #readObject()} for the effect caused by <code>close</code>.</p>
+ */
+ public void close()
+ {
+ if (isStreamClosed)
+ {
+ return;
+ }
+
+ try
+ {
+ inputStream.close();
+ isStreamClosed = true;
+ }
+ catch (IOException e)
+ {
+ // bad style forced by original API design ...
+ }
+ }
+
+ /** Returns the ExceptionListener instance associated with this decoder.
+ * <p>See the description of {@link XMLDecoder} class for more information on the ExceptionListener.</p>
+ *
+ * @return Current ExceptionListener of the decoder.
+ */
+ public ExceptionListener getExceptionListener()
+ {
+ return exceptionListener;
+ }
+
+ /** Returns the owner object of the decoder. This method is usually called
+ * from within the parsed XML data.
+ * <p>See the description of {@link XMLDecoder} class for more information on the owner object.</p>
+ *
+ * @return The owner object of this decoder.
+ */
+ public Object getOwner()
+ {
+ return owner;
+ }
+
+ /** Returns the next available decoded object.
+ * <p>Note that the actual decoding takes place when the method is called for the first time.</p>
+ * <p>If the <code>close</code> method was already called a <code>NoSuchElementException</code>
+ * is thrown.</p>
+ * <p>If the InputStream instance used in the constructors was <code>null</code> this method
+ * will always return <code>null</code> itself.</p>
+ *
+ * @return The next object in a sequence decoded from XML data.
+ * @throws ArrayIndexOutOfBoundsException When no more objects are available.
+ */
+ public Object readObject() throws ArrayIndexOutOfBoundsException
+ {
+ // note: the RI does it this way ...
+ if(inputStream == null) {
+ return null;
+ }
+
+ // note: the original API documentation says nothing on what to do
+ // when the stream was closed before readObject is called but it actually
+ // throws a NoSuchElementException - this behaviour is imitated here
+ if (isStreamClosed)
+ {
+ throw new NoSuchElementException("Cannot read any objects - XMLDecoder was already closed.");
+ }
+
+ // creates the PersistenceParser (doing the parsing and decoding) and returns its
+ // Iterator on first invocation
+ if (iterator == null)
+ {
+ iterator =
+ new PersistenceParser(
+ inputStream,
+ exceptionListener,
+ classLoader,
+ this)
+ .iterator();
+ }
+
+ // note: done according to the official documentation
+ if (!iterator.hasNext())
+ {
+ throw new ArrayIndexOutOfBoundsException("No more objects available from this XMLDecoder.");
+ }
+
+ // returns just the next object if there was no problem
+ return iterator.next();
+ }
+
+ /** Sets the ExceptionListener instance to which notifications of exceptions are send
+ * while parsing the XML data.
+ * <p>See the description of {@link XMLDecoder} class for more information on the ExceptionListener.</p>
+ *
+ * @param listener
+ */
+ public void setExceptionListener(ExceptionListener listener)
+ {
+ // uses a default implementation when null
+ if (listener == null)
+ {
+ listener = DefaultExceptionListener.INSTANCE;
+ }
+ exceptionListener = listener;
+ }
+
+ /** Sets the owner object which can be accessed from the parsed XML data.
+ * <p>See the description of {@link XMLDecoder} class for more information on the owner object.</p>
+ *
+ * @param newOwner
+ */
+ public void setOwner(Object newOwner)
+ {
+ owner = newOwner;
+ }
+
+}
diff --git a/libjava/classpath/java/beans/XMLEncoder.java b/libjava/classpath/java/beans/XMLEncoder.java
new file mode 100644
index 000000000..40cb6dbfb
--- /dev/null
+++ b/libjava/classpath/java/beans/XMLEncoder.java
@@ -0,0 +1,267 @@
+/* XMLEncoder.java
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.beans.encoder.ScanEngine;
+
+import java.io.OutputStream;
+
+/**
+ * This class uses the {@link PersistenceDelegate} and {@link Encoder}
+ * infrastructure to generate an XML representation of the objects it
+ * serializes.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.4
+ */
+public class XMLEncoder extends Encoder
+{
+ Object owner;
+
+ Exception exception;
+
+ ScanEngine scanEngine;
+
+ private int accessCounter = 0;
+
+ public XMLEncoder(OutputStream os)
+ {
+ scanEngine = new ScanEngine(os);
+ }
+
+ public void close()
+ {
+ if (scanEngine != null)
+ {
+ scanEngine.close();
+ scanEngine = null;
+ }
+ }
+
+ public void flush()
+ {
+ scanEngine.flush();
+ }
+
+ public void writeExpression(Expression expr)
+ {
+ // Implementation note: Why is this method overwritten and nearly exactly
+ // reimplemented as in Encoder?
+ // The Encoder class can (and should be) subclassed by users outside of the
+ // java.beans package. While I have doubts that this is possible from an
+ // API design point of view I tried to replicate the Encoder's behavior
+ // in the JDK as exactly as possible. This strictness however made it
+ // extremely complicated to implement the XMLEncoder's backend. Therefore
+ // I decided to copy the Encoder's implementation and make all changes
+ // I needed for a succesfull operation of XMLEncoder.
+ //
+ // The same is true for the writeStatement method.
+
+ // Silently ignore out of bounds calls.
+ if (accessCounter <= 0)
+ return;
+
+ scanEngine.writeExpression(expr);
+
+
+ Object target = expr.getTarget();
+ Object value = null;
+ Object newValue = null;
+
+ try
+ {
+ value = expr.getValue();
+ }
+ catch (Exception e)
+ {
+ getExceptionListener().exceptionThrown(e);
+ return;
+ }
+
+
+ newValue = get(value);
+
+ if (newValue == null)
+ {
+ Object newTarget = get(target);
+ if (newTarget == null)
+ {
+ writeObject(target);
+ newTarget = get(target);
+
+ // May happen if exception was thrown.
+ if (newTarget == null)
+ {
+ return;
+ }
+ }
+
+ Object[] args = expr.getArguments();
+ Object[] newArgs = new Object[args.length];
+
+ for (int i = 0; i < args.length; i++)
+ {
+ newArgs[i] = get(args[i]);
+ if (newArgs[i] == null || isImmutableType(args[i].getClass()))
+ {
+ writeObject(args[i]);
+ newArgs[i] = get(args[i]);
+ }
+ }
+
+ Expression newExpr = new Expression(newTarget, expr.getMethodName(),
+ newArgs);
+
+ // Fakes the result of Class.forName(<primitiveType>) to make it possible
+ // to hand such a type to the encoding process.
+ if (value instanceof Class && ((Class) value).isPrimitive())
+ newExpr.setValue(value);
+
+ // Instantiates the new object.
+ try
+ {
+ newValue = newExpr.getValue();
+
+ putCandidate(value, newValue);
+ }
+ catch (Exception e)
+ {
+ getExceptionListener().exceptionThrown(e);
+
+ // In Statement.writeExpression we had no possibility to flags
+ // an erroneous state to the ScanEngine without behaving different
+ // to the JDK.
+ scanEngine.revoke();
+
+ return;
+ }
+
+ writeObject(value);
+
+ }
+ else if(value.getClass() == String.class || value.getClass() == Class.class)
+ {
+ writeObject(value);
+ }
+
+ scanEngine.end();
+ }
+
+ public void writeStatement(Statement stmt)
+ {
+ // In case of questions have a at the implementation note in
+ // writeExpression.
+
+ scanEngine.writeStatement(stmt);
+
+ // Silently ignore out of bounds calls.
+ if (accessCounter <= 0)
+ return;
+
+ Object target = stmt.getTarget();
+
+ Object newTarget = get(target);
+ if (newTarget == null)
+ {
+ writeObject(target);
+ newTarget = get(target);
+ }
+
+ Object[] args = stmt.getArguments();
+ Object[] newArgs = new Object[args.length];
+
+ for (int i = 0; i < args.length; i++)
+ {
+ // Here is the difference to the original writeStatement
+ // method in Encoder. In case that the object is known or
+ // not an immutable we put it directly into the ScanEngine
+ // which will then generate an object reference for it.
+ newArgs[i] = get(args[i]);
+ if (newArgs[i] == null || isImmutableType(args[i].getClass()))
+ {
+ writeObject(args[i]);
+ newArgs[i] = get(args[i]);
+ }
+ else
+ scanEngine.writeObject(args[i]);
+ }
+
+ Statement newStmt = new Statement(newTarget, stmt.getMethodName(), newArgs);
+
+ try
+ {
+ newStmt.execute();
+ }
+ catch (Exception e)
+ {
+ getExceptionListener().exceptionThrown(e);
+
+ // In Statement.writeStatement we had no possibility to flags
+ // an erroneous state to the ScanEngine without behaving different
+ // to the JDK.
+ scanEngine.revoke();
+ return;
+ }
+
+ scanEngine.end();
+ }
+
+ public void writeObject(Object o)
+ {
+ accessCounter++;
+
+ scanEngine.writeObject(o);
+
+ if (get(o) == null)
+ super.writeObject(o);
+
+ accessCounter--;
+ }
+
+ public void setOwner(Object o)
+ {
+ owner = o;
+ }
+
+ public Object getOwner()
+ {
+ return owner;
+ }
+
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContext.java b/libjava/classpath/java/beans/beancontext/BeanContext.java
new file mode 100644
index 000000000..803cb36ff
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContext.java
@@ -0,0 +1,272 @@
+/* java.beans.beancontext.BeanContext
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.beans.DesignMode;
+import java.beans.Visibility;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+
+/**
+ * Acts as a container for sub-beans and as a sub-bean,
+ * so that an entire hierarchy of beans can be made up of
+ * <code>BeanContext</code>s.
+ * <P>
+ *
+ * Since I can't sprinkle the <code>Collections</code> interface
+ * documentation with special information for <code>BeanContext</code>
+ * implementors, I'll have to document special requirements for
+ * implementors of those functions here.
+ * <P>
+ *
+ * <code><strong>add()</strong></code> or <code>addAll()</code>:
+ * <br>
+ * <OL>
+ * <LI>
+ * May add any <code>Object</code> into the hierarchy as well as a
+ * <code>BeanContextChild</code>, <code>BeanContext</code> or
+ * <code>BeanContextProxy</code> object.
+ * This way, any Bean can be in the hierarchy.
+ * </LI>
+ * <LI>
+ * Must synchronize on <code>BeanContext.globalHierarchyLock</code>.
+ * </LI>
+ * <LI>
+ * Don't add the <code>Object</code> if it's already there (only once
+ * per <code>BeanContext</code>).
+ * </LI>
+ * <LI>
+ * If it is a <code>BeanContextChild</code> implementor, call
+ * <code>setBeanContext()</code> on it. If it's a
+ * <code>BeanContextProxy</code> implementor, call
+ * <code>getBeanContextProxy().setBeanContext()</code> on it.
+ * If <code>setBeanContext()</code> vetoes the change, back out
+ * all changes so far and throw <code>IllegalStateException</code>.
+ * </LI>
+ * <LI>
+ * If it (or its proxy) implements <code>Visibility</code>, call
+ * <code>dontUseGui()</code> or <code>okToUseGui()</code> on it,
+ * depending on whether you (the <code>BeanContext</code>) feel like
+ * allowing it to use the GUI or not.
+ * </LI>
+ * <LI>
+ * If it implements <code>BeanContextChild</code> or
+ * <code>BeanContextProxy</code>, register yourself (the
+ * <code>BeanContext</code>) as both a
+ * <code>PropertyChangeListener</code> and
+ * <code>VetoableChangeListener</code> on the "beanContext"
+ * property (it may also add itself on any other properties it wishes
+ * to).
+ * </LI>
+ * <LI>
+ * If it is a listener or event source that you (the
+ * <code>BeanContext</code>) are interested in, you may register
+ * yourself to it or register it to you.
+ * </LI>
+ * <LI>
+ * Fire a <code>java.beans.beancontext.BeanContextMembershipEvent</code>
+ * before exiting. <code>addAll()</code> should wait until everything
+ * is done changing before firing the event (or events) so that if a
+ * failure occurs, the backing-out process can proceed without any
+ * events being fired at all.
+ * </LI>
+ * </OL>
+ * <P>
+ *
+ * <code><strong>remove()</strong></code> or <code>removeAll()</code>:
+ * <br>
+ * <OL>
+ * <LI>
+ * Must synchronize on <code>BeanContext.globalHierarchyLock</code>.
+ * </LI>
+ * <LI>
+ * If the specified <code>Object</code> is not a child of this
+ * <code>BeanContext</code>, just exit without performing any actions.
+ * </LI>
+ * <LI>
+ * Remove the <code>Object</code> from your collection of children.
+ * </LI>
+ * <LI>
+ * If it is a <code>BeanContextChild</code> implementor, call
+ * <code>setBeanContext(null)</code> on it. If it's a
+ * <code>BeanContextProxy</code> implementor, call
+ * <code>getBeanContextProxy().setBeanContext(null)</code> on it.
+ * If <code>setBeanContext()</code> vetoes the change, back out
+ * all changes so far and throw <code>IllegalStateException</code>.
+ * </LI>
+ * <LI>
+ * If you registered the <code>Object</code> to listen to you or
+ * registered yourself as a listener on the <code>Object</code> during
+ * <code>add()</code> or <code>addAll()</code>, undo the registration
+ * bycalling the appropriate <code>removeListener()</code> method.
+ * </LI>
+ * <LI>
+ * Fire a <code>java.beans.beancontext.BeanContextMembershipEvent</code>
+ * before exiting. <code>removeAll()</code> should wait until
+ * everything is done changing before firing the event (or events) so
+ * that if a failure occurs, the backing-out process can proceed
+ * without any events being fired at all.
+ * </LI>
+ * </OL>
+ * <P>
+ *
+ * <code>addAll()</code>, <code>removeAll()</code>,
+ * <code>retainAll()</code> and <code>clear()</code> do not need to be
+ * implemented, but may be if so desired.
+ * <P>
+ *
+ * Similarly, <code>Visibility</code> and <code>DesignMode</code> methods
+ * should propagate changed values to children that implement interfaces
+ * of the same name.
+ * <P>
+ *
+ * A hierarchy of beans is mainly useful so that different sets of beans
+ * can be established, each with their own set of resources.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContext
+ extends Collection, BeanContextChild, Visibility, DesignMode {
+
+ /**
+ * The global lock on changing any BeanContext hierarchy.
+ * It kinda sucks that there is only one lock, since there can be
+ * multiple hierarchies. Oh well, I didn't design, I just code.
+ * <P>
+ *
+ * Methods that must (or do) synchronize on the global lock:
+ * <BR>
+ * <UL>
+ * <LI>
+ * Implementors of <CODE>BeanContext.add()</CODE> and <code>addAll()</code>
+ * </LI>
+ * </UL>
+ * @fixme fill in the rest of the methods which use the global lock.
+ */
+ Object globalHierarchyLock = new Object();
+
+ /**
+ * Instantiate a Bean using this Bean's <code>ClassLoader</code>
+ * and this <code>BeanContext</code> as the parent.
+ * <P>
+ *
+ * This method exists mainly so that <code>BeanContext</code>
+ * implementations can perform extra actions on Beans that are
+ * created within them.
+ *
+ * @param beanName the name of the bean to instantiate
+ * @return the created Bean
+ *
+ * @see java.beans.Beans#instantiate(java.lang.ClassLoader,java.lang.String)
+ * @see java.beans.Beans#instantiate(java.lang.ClassLoader,java.lang.String,java.beans.beancontext.BeanContext)
+ * @exception IOException if there is an I/O problem during
+ * instantiation.
+ * @exception ClassNotFoundException if a serialized Bean's class
+ * is not found.
+ */
+ Object instantiateChild(String beanName)
+ throws IOException,
+ ClassNotFoundException;
+
+ /**
+ * Get a resource. The <code>BeanContext</code> will typically
+ * call <code>ClassLoader.getResource()</code>, but may do it any
+ * way it wants to. This allows a <code>BeanContext</code> to
+ * have its own set of resources separate from the rest of the
+ * system.
+ * <P>
+ *
+ * Beans should call this method on their parent rather than the
+ * associated <code>ClassLoader</code> method.
+ * <P>
+ *
+ * I am assuming, but am not entirely sure, that if a
+ * <code>BeanContext</code> cannot find a resource, its
+ * responsibility is to call the <code>getResource</code> method
+ * of its parent <code>BeanContext</code>.
+ *
+ * @return a URL to the requested resource.
+ * @param resourceName the name of the resource requested.
+ * @param requestor a reference to the child requesting the resource.
+ * @see java.lang.ClassLoader#getResource(java.lang.String)
+ */
+ URL getResource(String resourceName, BeanContextChild requestor);
+
+ /**
+ * Get a resource as a stream. The <code>BeanContext</code> will
+ * typically call <code>ClassLoader.getResourceAsStream()</code>,
+ * but may do it any way it wants to. This allows a
+ * <code>BeanContext</code>'s children to have their own set of
+ * resources separate from the rest of the system.
+ * <P>
+ *
+ * Beans should call this method on their parent rather than the
+ * associated <code>ClassLoader</code> method.
+ * <P>
+ *
+ * I am assuming, but am not entirely sure, that if a
+ * <code>BeanContext</code> cannot find a resource, its
+ * responsibility is to call the <code>getResourceAsStream</code>
+ * method of its parent <code>BeanContext</code>.
+ *
+ * @return the requested resource as a stream.
+ * @param resourceName the name of the resource requested.
+ * @param requestor a reference to the child requesting the resource.
+ * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
+ */
+ InputStream getResourceAsStream(String resourceName, BeanContextChild requestor);
+
+ /**
+ * Add a listener on changes to the membership of this
+ * <code>BeanContext</code> object.
+ * @param listener the listener to add.
+ */
+ void addBeanContextMembershipListener(BeanContextMembershipListener listener);
+
+ /**
+ * Remove a listener on changes to the membership of this
+ * <code>BeanContext</code> object.
+ * @param listener the listener to remove.
+ */
+ void removeBeanContextMembershipListener(BeanContextMembershipListener listener);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextChild.java b/libjava/classpath/java/beans/beancontext/BeanContextChild.java
new file mode 100644
index 000000000..e2bdcf336
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextChild.java
@@ -0,0 +1,174 @@
+/* java.beans.beancontext.BeanContextChild
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+
+/**
+ * Beans implement this to get information about the execution environment and
+ * its services and to be placed in the hierarchy.
+ * <P>
+ *
+ * The difference between a <code>BeanContext</code> and a
+ * <code>BeanContextChild</code>, mainly, is that a
+ * <code>BeanContext</code> may be a parent.
+ * <P>
+ *
+ * <code>BeanContextChild</code> instances will be serialized at some
+ * point in their life, but you need to make sure your bean context does
+ * not contain a serializable reference (directly or indirectly) to the
+ * parent <code>BeanContext</code>, to any of the other
+ * <code>BeanContext</code>s in the tree, or to any resources obtained
+ * via the <code>BeanContextServices</code> interface. One way to do this
+ * is to mark any fields that contain such references as
+ * <code>transient</code>. Another way is to use a custom serializer.
+ * <P>
+ *
+ * If you do not do this, when the <code>BeanContext</code> is serialized,
+ * all the other <code>BeanContext</code>s and other unnecessary things
+ * will be serialized along with it.
+ * <P>
+ *
+ * Before dying, a <code>BeanContextChild</code> should call
+ * <code>getBeanContext().remove(this)</code> to detach from the
+ * hierarchy and exit cleanly.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ * @see java.beans.beancontext.BeanContext
+ */
+
+public interface BeanContextChild {
+ /**
+ * Set the parent <code>BeanContext</code>.
+ * <P>
+ *
+ * This method is called from <code>BeanContext.add()</code> and
+ * should not be called directly.
+ * <P>
+ *
+ * When this Object is being added to a new BeanContext or moved
+ * from an old one, a non-null value will be passed in.
+ * <P>
+ *
+ * When this Object is being removed from the current
+ * <code>BeanContext</code>, <code>setBeanContext()</code> will
+ * receive the parameter <code>null</code>.
+ * <P>
+ *
+ * When being removed from the current <code>BeanContext</code>,
+ * it is the <code>BeanContextChild</code>'s responsibility to
+ * release all services it has obtained.
+ * <P>
+ *
+ * This change should generate <code>PropertyChangeEvent</code>
+ * and <code>VetoableChangeEvent</code>s with the property name
+ * "beanContext". If the change is vetoed, it must re-throw the
+ * exception and not change anything. In this way, the parent
+ * <code>BeanContextChild</code>, who has registered himself with
+ * you, will have a chance to remove this child from its
+ * collection.
+ * <P>
+ *
+ * If the Bean does not wish to change the parent or be removed
+ * from one, it may throw the <code>PropertyVetoException</code>.
+ * If you veto a <code>setBeanContext(null)</code> call, then you
+ * should try your hardest to remedy whatever problem is keeping
+ * you from being removed from the <code>BeanContext</code> so
+ * that you can <em>not</em> veto it the next time.
+ * Otherwise, nasty pathological recursion stuff could occur in
+ * certain situations.
+ * <P>
+ *
+ * If you do veto the change, you must first back out any changes
+ * you made prior to the veto. Best not to make any such changes
+ * prior to the veto in the first place.
+ * <P>
+ *
+ * This method is called from <code>BeanContext.add()</code> and
+ * should not be called directly.
+ *
+ * @param parent the new parent for the <code>BeanContextChild</code>,
+ * or <code>null</code> to signify removal from a tree.
+ * @exception PropertyVetoException if the
+ * <code>BeanContextChild</code> implementor does not
+ * wish to have its parent changed.
+ */
+ void setBeanContext(BeanContext parent)
+ throws PropertyVetoException;
+
+ /**
+ * Get the parent <code>BeanContext</code>.
+ * @return the parent <code>BeanContext</code>.
+ */
+ BeanContext getBeanContext();
+
+ /**
+ * Add a listener that will be notified when a specific property changes.
+ * @param prop the name of the property to listen on
+ * @param listener the listener to listen on the property.
+ */
+ void addPropertyChangeListener(String prop, PropertyChangeListener listener);
+
+ /**
+ * Remove a listener to a certain property.
+ * @param prop the name of the property being listened on
+ * @param listener the listener listening on the property.
+ */
+ void removePropertyChangeListener(String prop, PropertyChangeListener listener);
+
+ /**
+ * Add a listener that will be notified when a specific property
+ * change is requested (a PropertyVetoException may be thrown) as
+ * well as after the change is successfully made.
+ *
+ * @param prop the name of the property to listen on
+ * @param listener the listener to listen on the property.
+ */
+ void addVetoableChangeListener(String prop, VetoableChangeListener listener);
+
+ /**
+ * Remove a listener to a certain property.
+ * @param prop the name of the property being listened on
+ * @param listener the listener listening on the property.
+ */
+ void removeVetoableChangeListener(String prop, VetoableChangeListener listener);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java b/libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java
new file mode 100644
index 000000000..cb75d508d
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java
@@ -0,0 +1,60 @@
+/* java.beans.beancontext.BeanContextChildComponentProxy
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.awt.Component;
+
+/**
+ * Interface for <code>BeanContextChild</code>s which wish to associate an
+ * AWT component with them. The proxy is provided because the
+ * <code>addPropertyChangeListener()</code> method would conflict with
+ * <code>Component</code> if you tried to extend.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextChildComponentProxy {
+ /**
+ * Get the <code>Component</code> associated with this <code>BeanContextChild</code>.
+ * @return the <code>Component</code> associated with this
+ * <code>BeanContextChild</code>.
+ */
+ Component getComponent();
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java
new file mode 100644
index 000000000..8cd887d0c
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java
@@ -0,0 +1,381 @@
+/* java.beans.beancontext.BeanContextChildSupport
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+import java.beans.VetoableChangeSupport;
+import java.io.Serializable;
+
+/**
+ * Support for creating a <code>BeanContextChild</code>.
+ * This class contains the most common implementations of the methods in
+ * the <code>BeanContextChild</code>
+ *
+ * @specnote This class is not very well specified. I had to "fill in the
+ * blanks" in most places with what I thought was reasonable
+ * behavior. If there are problems, let me know.
+ *
+ * @author John Keiser
+ * @since 1.2
+ * @see java.beans.beancontext.BeanContextChild
+ */
+public class BeanContextChildSupport
+ implements BeanContextChild, BeanContextServicesListener, Serializable
+{
+ static final long serialVersionUID = 6328947014421475877L;
+
+ /**
+ * The peer on which to perform <code>set</code> actions.
+ * This is here so that this class can be used as a peer.
+ * <P>
+ *
+ * When extending this class, this variable will be set to
+ * <code>this</code>.
+ */
+ public BeanContextChild beanContextChildPeer;
+
+ /**
+ * The parent <code>BeanContext</code>.
+ */
+ protected transient BeanContext beanContext;
+
+ /**
+ * If <code>setBeanContext()</code> was vetoed once before, this
+ * is set to <code>true</code> so that the next time, vetoes will
+ * be ignored.
+ */
+ protected transient boolean rejectedSetBCOnce;
+
+ /**
+ * Listeners are registered here and events are fired through here.
+ */
+ protected PropertyChangeSupport pcSupport;
+
+ /**
+ * Listeners are registered here and events are fired through here.
+ */
+ protected VetoableChangeSupport vcSupport;
+
+ /**
+ * Create a new <code>BeanContextChildSupport</code> with itself as the peer.
+ * This is meant to be used when you subclass
+ * <code>BeanContextChildSupport</code> to create your child.
+ */
+ public BeanContextChildSupport()
+ {
+ this (null);
+ }
+
+ /**
+ * Create a new <code>BeanContextChildSupport</code> with the specified peer.
+ * @param peer the peer to use, or <code>null</code> to specify
+ * <code>this</code>.
+ */
+ public BeanContextChildSupport (BeanContextChild peer)
+ {
+ if (peer == null)
+ {
+ peer = this;
+ }
+
+ beanContextChildPeer = peer;
+ pcSupport = new PropertyChangeSupport (peer);
+ vcSupport = new VetoableChangeSupport (peer);
+ }
+
+ /**
+ * Set the parent <code>BeanContext</code>.
+ * <P>
+ *
+ * When this Object is being added to a new BeanContext or moved
+ * from an old one, a non-null value will be passed in.
+ * <P>
+ *
+ * When this Object is being removed from the current
+ * <code>BeanContext</code>, <code>setBeanContext()</code> will
+ * receive the parameter <code>null</code>.
+ * <P>
+ *
+ * Order of events:
+ * <OL>
+ * <LI>
+ * If the new <code>BeanContext</code> is the same as the old
+ * one, nothing happens.
+ * </LI>
+ * <LI>
+ * If the change has not been rejected or vetoed before, call
+ * <code>validatePendingSetBeanContext()</code>. If this call
+ * returns <code>false</code>, the change is rejected and a
+ * <code>PropertyVetoException</code> is thrown.
+ * </LI>
+ * <LI>
+ * If the change has not been rejected or vetoed before,
+ * <code>VetoableChangeEvent</code>s are fired with the name
+ * <code>"beanContext"</code>, using the
+ * <code>fireVetoableChange()</code> method. If a veto
+ * occurs, reversion events are fired using the same method,
+ * the change is rejected, and the veto is rethrown.
+ * </LI>
+ * <LI>
+ * <code>releaseBeanContextResources()</code> is called.
+ * </LI>
+ * <LI>
+ * The change is made.
+ * </LI>
+ * <LI>
+ * <code>PropertyChangeEvent</code>s are fired using the
+ * <code>firePropertyChange()</code> method.
+ * </LI>
+ * <LI>
+ * <code>initializeBeanContextResources()</code> is called.
+ * </LI>
+ * </OL>
+ * <P>
+ *
+ * @param newBeanContext the new parent for the
+ * <code>BeanContextChild</code>, or <code>null</code> to
+ * signify removal from a tree.
+ * @exception PropertyVetoException if the
+ * <code>BeanContextChild</code> implementor does not
+ * wish to have its parent changed.
+ */
+ public void setBeanContext(BeanContext newBeanContext)
+ throws PropertyVetoException
+ {
+ synchronized (beanContextChildPeer)
+ {
+ if (newBeanContext == beanContext)
+ return;
+
+ if (!rejectedSetBCOnce)
+ {
+ if (!validatePendingSetBeanContext (newBeanContext))
+ {
+ rejectedSetBCOnce = true;
+ throw new PropertyVetoException ("validatePendingSetBeanContext() rejected change",
+ new PropertyChangeEvent(beanContextChildPeer, "beanContext", beanContext, newBeanContext));
+ }
+
+ try
+ {
+ fireVetoableChange ("beanContext", beanContext, newBeanContext);
+ }
+ catch (PropertyVetoException e)
+ {
+ rejectedSetBCOnce = true;
+ throw e;
+ }
+ }
+
+ releaseBeanContextResources ();
+
+ beanContext = newBeanContext;
+ rejectedSetBCOnce = false;
+
+ firePropertyChange ("beanContext", beanContext, newBeanContext);
+
+ initializeBeanContextResources ();
+ }
+ }
+
+ /**
+ * Get the parent <code>BeanContext</code>.
+ * @return the parent <code>BeanContext</code>.
+ */
+ public BeanContext getBeanContext()
+ {
+ return beanContext;
+ }
+
+ /**
+ * Get the peer (or <code>this</code> if there is no peer).
+ * @return the peer, or <code>this</code> if there is no peer.
+ */
+ public BeanContextChild getBeanContextChildPeer() {
+ return beanContextChildPeer;
+ }
+
+ /**
+ * Determine whether there is a peer.
+ * This is true iff <code>getBeanContextChildPeer() == this</code>.
+ * @return whether there is a peer.
+ */
+ public boolean isDelegated() {
+ return beanContextChildPeer == this;
+ }
+
+ /**
+ * Add a listener that will be notified when a specific property changes.
+ * @param propertyName the name of the property to listen on.
+ * @param listener the listener to listen on the property.
+ */
+ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ pcSupport.addPropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Remove a listener to a certain property.
+ *
+ * @param propertyName the name of the property being listened on.
+ * @param listener the listener listening on the property.
+ */
+ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ pcSupport.removePropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Add a listener that will be notified when a specific property
+ * change is requested (a PropertyVetoException may be thrown) as
+ * well as after the change is successfully made.
+ *
+ * @param propertyName the name of the property to listen on.
+ * @param listener the listener to listen on the property.
+ */
+ public void addVetoableChangeListener(String propertyName, VetoableChangeListener listener) {
+ vcSupport.addVetoableChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Remove a listener to a certain property.
+ *
+ * @param propertyName the name of the property being listened on
+ * @param listener the listener listening on the property.
+ */
+ public void removeVetoableChangeListener(String propertyName, VetoableChangeListener listener) {
+ vcSupport.removeVetoableChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Fire a property change.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value of the property
+ * @param newVal the new value of the property
+ */
+ public void firePropertyChange(String propertyName, Object oldVal, Object newVal) {
+ pcSupport.firePropertyChange(propertyName, oldVal, newVal);
+ }
+
+ /**
+ * Fire a vetoable property change.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value of the property
+ * @param newVal the new value of the property
+ * @exception PropertyVetoException if the change is vetoed.
+ */
+ public void fireVetoableChange(String propertyName, Object oldVal, Object newVal)
+ throws PropertyVetoException {
+ vcSupport.fireVetoableChange(propertyName, oldVal, newVal);
+ }
+
+ /**
+ * Called by <code>BeanContextServices.revokeService()</code> to indicate that a service has been revoked.
+ * If you have a reference to such a service, it should be
+ * discarded and may no longer function properly.
+ * <code>getService()</code> will no longer work on the specified
+ * service class after this event has been fired.
+ * <P>
+ *
+ * <EM>This method is meant to be overriden.</EM>
+ * <code>BeanContextChildSupport</code>'s implementation does
+ * nothing.
+ *
+ * @param event the service revoked event.
+ * @see java.beans.beancontext.BeanContextServices#revokeService(java.lang.Class,java.beans.beancontext.BeanContextServiceProvider,boolean)
+ */
+ public void serviceRevoked(BeanContextServiceRevokedEvent event) {
+ }
+
+ /**
+ * Called by <code>BeanContextServices</code> whenever a service is made available.
+ * <P>
+ *
+ * <EM>This method is meant to be overriden.</EM>
+ * <code>BeanContextChildSupport</code>'s implementation does
+ * nothing.
+ *
+ * @param event the service revoked event, with useful information
+ * about the new service.
+ */
+ public void serviceAvailable(BeanContextServiceAvailableEvent event) {
+ }
+
+ /**
+ * Called by <code>setBeanContext()</code> to determine whether the set should be rejected.
+ * <P>
+ *
+ * <EM>This method is meant to be overriden.</EM>
+ * <code>BeanContextChildSupport</code>'s implementation simply
+ * returns <code>true</code>.
+ *
+ * @param newBeanContext the new parent.
+ * @return whether to allow the parent to be changed to the new
+ * value.
+ */
+ public boolean validatePendingSetBeanContext(BeanContext newBeanContext) {
+ return true;
+ }
+
+ /**
+ * Called by <code>setBeanContext()</code> to release resources of a what will soon no longer be the parent.
+ * <P>
+ *
+ * <EM>This method is meant to be overriden.</EM>
+ * <code>BeanContextChildSupport</code>'s implementation does
+ * nothing.
+ */
+ protected void releaseBeanContextResources() {
+ }
+
+ /**
+ * Called by <code>setBeanContext()</code> to grab resources when the parent has been set.
+ * <P>
+ *
+ * <EM>This method is meant to be overriden.</EM>
+ * <code>BeanContextChildSupport</code>'s implementation does
+ * nothing.
+ */
+ protected void initializeBeanContextResources() {
+ }
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java b/libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java
new file mode 100644
index 000000000..962cb5fc9
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java
@@ -0,0 +1,63 @@
+/* java.beans.beancontext.BeanContextContainerProxy
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.awt.Container;
+
+/**
+ * Interface for <code>BeanContext</code>s which wish to associate an
+ * AWT container with them. The proxy is provided because the
+ * <code>addPropertyChangeListener()</code> and <code>add()</code> methods
+ * would conflict with <code>Component</code> and <code>Container</code>
+ * if you tried to extend.
+ *
+ * @specnote It is unclear whether anything besides <code>BeanContext</code>s
+ * are allowed to implement this interface.
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextContainerProxy {
+ /**
+ * Get the <code>Container</code> associated with this <code>BeanContext</code>.
+ * @return the <code>Container</code> associated with this
+ * <code>BeanContext</code>.
+ */
+ Container getContainer();
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextEvent.java
new file mode 100644
index 000000000..959d54e58
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextEvent.java
@@ -0,0 +1,110 @@
+/* java.beans.beancontext.BeanContextEvent
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.EventObject;
+
+/**
+ * Generic superclass for events fired by <code>BeanContext</code>s.
+ *
+ * @author John Keiser
+ * @since 1.2
+ */
+
+public abstract class BeanContextEvent extends EventObject
+{
+ private static final long serialVersionUID = 7267998073569045052L;
+
+ /**
+ * The <code>BeanContext</code> that most recently passed this
+ * event on.
+ */
+ protected BeanContext propagatedFrom;
+
+ /**
+ * Create a new event, from the specified <code>BeanContext</code>.
+ * <code>propagatedFrom</code> will be initialized to
+ * <code>null</code>.
+ *
+ * @param source the source of the event.
+ */
+ protected BeanContextEvent(BeanContext source)
+ {
+ super(source);
+ }
+
+ /**
+ * Get the <code>BeanContext</code> that originated this event.
+ * @return the originator of this event.
+ */
+ public BeanContext getBeanContext()
+ {
+ return (BeanContext)getSource();
+ }
+
+ /**
+ * Get the most recent propagator of this event.
+ * If this value is <code>null</code>, you have received the event
+ * straight from the source.
+ *
+ * @return the most recent propagator of this event.
+ */
+ public BeanContext getPropagatedFrom()
+ {
+ return propagatedFrom;
+ }
+
+ /**
+ * Tell whether this event has been propagated.
+ * @return <code>true</code> iff <code>getPropagatedFrom() != null</code>.
+ */
+ public boolean isPropagated()
+ {
+ return propagatedFrom != null;
+ }
+
+ /**
+ * Set the most recent propagator of this event.
+ * @param propagator the most recent propagator of this event.
+ */
+ public void setPropagatedFrom(BeanContext propagator)
+ {
+ propagatedFrom = propagator;
+ }
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java
new file mode 100644
index 000000000..77b1be43e
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java
@@ -0,0 +1,114 @@
+/* java.beans.beancontext.BeanContextMembershipEvent
+ Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Event fired when children are added to or removed from a <code>BeanContext</code>.
+ * Whether they were added or removed depends entirely on which method
+ * of the listener interface was called.
+ *
+ * @author John Keiser
+ * @since 1.2
+ * @see java.beans.beancontext.BeanContextMembershipListener
+ */
+public class BeanContextMembershipEvent extends BeanContextEvent {
+ private static final long serialVersionUID = 3499346510334590959L;
+
+ /**
+ * The children that were added or removed.
+ */
+ protected Collection children;
+
+ /**
+ * Create a new membership event.
+ * @param context the event source.
+ * @param children the children added to or removed from the source.
+ */
+ public BeanContextMembershipEvent(BeanContext context, Collection children) {
+ super(context);
+ this.children = children;
+ }
+
+ /**
+ * Create a new membership event.
+ * @param context the event source.
+ * @param children the children added to or removed from the source.
+ */
+ public BeanContextMembershipEvent(BeanContext context, Object[] children) {
+ super(context);
+ this.children = Arrays.asList(children);
+ }
+
+ /**
+ * The number of children removed or added.
+ * @return the number of children removed or added.
+ */
+ public int size() {
+ return children.size();
+ }
+
+ /**
+ * An iterator that will step through all the children.
+ * @return an iterator over all the children.
+ */
+ public Iterator iterator() {
+ return children.iterator();
+ }
+
+ /**
+ * An array of the children.
+ * @return an array of the children.
+ */
+ public Object[] toArray() {
+ return children.toArray();
+ }
+
+ /**
+ * Tell whether the <code>Object</code> is one of the children added or removed.
+ * @param child the child to check.
+ * @return whether the <code>Object</code> is added or removed.
+ */
+ public boolean contains(Object child) {
+ return children.contains(child);
+ }
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java b/libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java
new file mode 100644
index 000000000..cdb47c811
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java
@@ -0,0 +1,70 @@
+/* java.beans.beancontext.BeanContextMembershipListener
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.EventListener;
+
+/**
+ * This is the interface to which <code>BeanContextMembershipEvent</code>s are sent.
+ * This happens when children are added to or removed from a
+ * <code>BeanContext</code>.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextMembershipListener extends EventListener {
+ /**
+ * When beans are added to a <code>BeanContext</code>,
+ * this method is called to fire the event.
+ *
+ * @param event the event, including which children were added.
+ * @see java.beans.beancontext.BeanContext#add(java.lang.Object)
+ */
+ void childrenAdded(BeanContextMembershipEvent event);
+
+ /**
+ * When beans are removed from a <code>BeanContext</code>,
+ * this method is called to fire the event.
+ *
+ * @param event the event, including which children were removed.
+ * @see java.beans.beancontext.BeanContext#remove(java.lang.Object)
+ */
+ void childrenRemoved(BeanContextMembershipEvent event);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextProxy.java b/libjava/classpath/java/beans/beancontext/BeanContextProxy.java
new file mode 100644
index 000000000..53632e86b
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextProxy.java
@@ -0,0 +1,65 @@
+/* java.beans.beancontext.BeanContextProxy
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+/**
+ * Beans that wish to have a <code>BeanContextChild</code> or <code>BeanContext</code> associated with them
+ * but do not wish to implement those interfaces directly, can implement this interface.
+ * <P>
+ *
+ * Don't shoot yourself in the foot: if you already implement
+ * <code>BeanContextChild</code>, directly or indirectly, the whole
+ * workings of this package will be unpredictable because it is
+ * indeterminate as to whether the <code>BeanContextChild</code> is used
+ * in preference to its proxy or vice versa.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextProxy {
+ /**
+ * Return the <code>BeanContextChild</code> associated with this
+ * <code>Object</code>.
+ *
+ * @return the <code>BeanContextChild</code> associated with this
+ * <code>Object</code>.
+ */
+ BeanContextChild getBeanContextProxy();
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java
new file mode 100644
index 000000000..a2bdcdde7
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java
@@ -0,0 +1,97 @@
+/* java.beans.beancontext.BeanContextServiceAvailableEvent
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.Iterator;
+
+/**
+ * Event fired when new services become available through a <code>BeanContextServices</code>.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ * @see java.beans.beancontext.BeanContextServicesListener
+ */
+
+public class BeanContextServiceAvailableEvent extends BeanContextEvent {
+ private static final long serialVersionUID = -5333985775656400778L;
+
+ /**
+ * The <code>Class</code> representing the service which is now
+ * available.
+ */
+ protected Class serviceClass;
+
+ /**
+ * Create a new service available event.
+ * @param services the <code>BeanContextServices</code> through
+ * which the service is available. This is also the source
+ * of the event.
+ * @param serviceClass the service class that is now available.
+ */
+ public BeanContextServiceAvailableEvent(BeanContextServices services, Class serviceClass) {
+ super(services);
+ this.serviceClass = serviceClass;
+ }
+
+ /**
+ * Get the current service selectors of the service class.
+ * This is identical to <code>getSourceAsBeanContextServices().getCurrentServiceSelectors(getServiceClass())</code>
+ * @return the current service selectors of the service class.
+ */
+ public Iterator getCurrentServiceSelectors() {
+ return getSourceAsBeanContextServices().getCurrentServiceSelectors(serviceClass);
+ }
+
+ /**
+ * Get the newly available service class.
+ * @return the service class.
+ */
+ public Class getServiceClass() {
+ return serviceClass;
+ }
+
+ /**
+ * Get the <code>BeanContextServices</code> through which the new service is available.
+ * @return the <code>BeanContextServices</code> through which the
+ * new service is available.
+ */
+ public BeanContextServices getSourceAsBeanContextServices() {
+ return (BeanContextServices)getSource();
+ }
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java
new file mode 100644
index 000000000..7475a61bd
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java
@@ -0,0 +1,138 @@
+/* java.beans.beancontext.BeanContextServiceProvider
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.Iterator;
+
+/**
+ * An actual factory for services.
+ * <P>
+ *
+ * It is the <code>BeanContextServiceProvider</code>'s responsibility to
+ * register itself with whatever <code>BeanContextServices</code> object
+ * it wishes to provide services through using the
+ * <code>addService()</code> method.
+ * <P>
+ *
+ * If for some reason it can no longer provide services for a particular
+ * class, this class must invoke
+ * <code>BeanContextServices.revokeService(serviceClass,this,true)</code>
+ * for all the places it has registered the service.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextServiceProvider {
+ /**
+ * Get a service.
+ * Called from <code>BeanContextServices.getService()</code>.
+ *
+ * <p>If the requested service class is not available, or if this
+ * <code>BeanContextServiceProvider</code> chooses not honor the
+ * request for some reason, then this method will return
+ * <code>null</code>.</p>
+ *
+ * This method may throw unchecked exceptions, so watch out.
+ *
+ * @param services the <code>BeanContextServices</code> that wants
+ * to get the service. Only weak references to this will
+ * be retained, and it will never be changed, only queried
+ * in a read-only manner.
+ * @param requestor the actual requestor of the service. Only
+ * weak references to this will be retained, and it will
+ * never be changed, only queried in a read-only manner.
+ * @param serviceClass the <code>Class</code> of the service being
+ * requested.
+ * @param serviceSelector a parameter to customize the service
+ * returned with.
+ * @return an instance of <code>serviceClass</code> (such that
+ * <code>instanceof</code> serviceClass is true), or
+ * <code>null</code>.
+ * @see java.beans.beancontext.BeanContextServices#getService(java.beans.beancontext.BeanContextChild,java.lang.Object,java.lang.Class,java.lang.Object,java.beans.beancontext.BeanContextServiceRevokedListener)
+ */
+ Object getService(BeanContextServices services, Object requestor, Class serviceClass, Object serviceSelector);
+
+ /**
+ * Release the service.
+ * <P>
+ *
+ * Called by <code>BeanContextServices.releaseService()</code>.
+ * <P>
+ *
+ * Most <code>BeanContextServiceProvider</code>s won't have to do
+ * anything here.
+ *
+ * @param services the <code>BeanContextServices</code> that wants
+ * to release the service. Only weak references to this will
+ * be retained, and it will never be changed, only queried
+ * in a read-only manner.
+ * @param requestor the original requestor of the service.
+ * @param service the service to relinquish
+ * @see java.beans.beancontext.BeanContextServices#releaseService(java.beans.beancontext.BeanContextChild,java.lang.Object,java.lang.Object)
+ */
+ void releaseService(BeanContextServices services, Object requestor, Object service);
+
+ /**
+ * Get a list of valid service selectors for the specified service class.
+ * This method is called from
+ * <code>BeanContextServices.getCurrentServiceSelectors()</code>.
+ * <P>
+ *
+ * If the specified service class does not have a finite number of
+ * valid service selectors, it should return <code>null</code>.
+ * If it takes a general <code>Integer</code> parameter, for
+ * example, you may as well return <code>null</code> or the poor
+ * soul who called this method will be iterating all day.
+ * <P>
+ *
+ * If it has no valid service selectors, it should still return an empty
+ * <code>Iterator</code>.
+ *
+ * @param services the <code>BeanContextServices</code> that wants
+ * to get the service selectors. Only weak references to this will
+ * be retained, and it will never be changed, only queried
+ * in a read-only manner.
+ * @param serviceClass the service class to get selectors for.
+ * @return a list of valid service selectors for the service
+ * class, or <code>null</code>.
+ * @see java.beans.beancontext.BeanContextServices#getCurrentServiceSelectors(java.lang.Class)
+ */
+ Iterator getCurrentServiceSelectors(BeanContextServices services, Class serviceClass);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java
new file mode 100644
index 000000000..78bfc200d
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java
@@ -0,0 +1,60 @@
+/* java.beans.beancontext.BeanContextServiceProviderBeanInfo
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.beans.BeanInfo;
+
+/**
+ * <code>BeanContextServiceProvider</code>s implement this to provide information about all of the services they provide.
+ * <P>
+ *
+ * This is apparently so that you can import a bunch of services into a
+ * RAD tool and it will know about all of them and export them to the
+ * user in a readable manner.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+public interface BeanContextServiceProviderBeanInfo extends BeanInfo {
+ /**
+ * Get <code>BeanInfo</code>s for all of the service classes of this <code>BeanInfoServiceProvider</code>.
+ * @return <code>BeanInfo</code>s for all provided service classes.
+ */
+ BeanInfo[] getServicesBeanInfo();
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java
new file mode 100644
index 000000000..b4f2fa856
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java
@@ -0,0 +1,112 @@
+/* java.beans.beancontext.BeanContextServiceRevokedEvent
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+/**
+ * Event fired when services are revoked from a <code>BeanContextServices</code>.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ * @see java.beans.beancontext.BeanContextServiceRevokedListener
+ */
+
+public class BeanContextServiceRevokedEvent extends BeanContextEvent {
+ private static final long serialVersionUID = -1295543154724961754L;
+
+ /**
+ * The <code>Class</code> representing the service which is now
+ * available.
+ */
+ protected Class serviceClass;
+ private boolean invalidateRefs;
+
+ /**
+ * Create a new service revoked event.
+ * @param services the <code>BeanContextServices</code> through
+ * which the service was available. This is also the source
+ * of the event.
+ * @param serviceClass the service class that is now revoked.
+ * @param revokeNow whether the revocation is immediate for all
+ * classes or just a suggestion.
+ */
+ public BeanContextServiceRevokedEvent(BeanContextServices services, Class serviceClass, boolean revokeNow) {
+ super(services);
+ this.serviceClass = serviceClass;
+ invalidateRefs = revokeNow;
+ }
+
+ /**
+ * Get the revoked service class.
+ * @return the service class.
+ */
+ public Class getServiceClass() {
+ return serviceClass;
+ }
+
+ /**
+ * Tell whether the revoked service class is the same as the specified class.
+ * Identical to <code>getServiceClass().equals(c)</code>.
+ * @param c the class to compare.
+ * @return whether the clases are equal.
+ */
+ public boolean isServiceClass(Class c) {
+ return serviceClass.equals(c);
+ }
+
+ /**
+ * Get the <code>BeanContextServices</code> through which the service was available.
+ * @return the <code>BeanContextServices</code> through which the
+ * service was available.
+ */
+ public BeanContextServices getSourceAsBeanContextServices() {
+ return (BeanContextServices)getSource();
+ }
+
+ /**
+ * Tell whether current instances of the revoked service are usable or not.
+ * This is determined by whether the service was revoked
+ * immediately.
+ *
+ * @return whether current instances of the revoked service are
+ * usable.
+ */
+ public boolean isCurrentServiceInvalidNow() {
+ return invalidateRefs;
+ }
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java
new file mode 100644
index 000000000..11b83dd65
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java
@@ -0,0 +1,62 @@
+/* java.beans.beancontext.BeanContextServiceRevokedListener
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.EventListener;
+
+/**
+ * Listens for service revoke events.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextServiceRevokedListener extends EventListener {
+ /**
+ * Called by <code>BeanContextServices.revokeService()</code> to indicate that a service has been revoked.
+ * If you have a reference to such a service, it should be
+ * discarded and may no longer function properly.
+ * <code>getService()</code> will no longer work on the specified
+ * service class after this event has been fired.
+ *
+ * @param event the service revoked event.
+ * @see java.beans.beancontext.BeanContextServices#revokeService(java.lang.Class,java.beans.beancontext.BeanContextServiceProvider,boolean)
+ */
+ void serviceRevoked(BeanContextServiceRevokedEvent event);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServices.java b/libjava/classpath/java/beans/beancontext/BeanContextServices.java
new file mode 100644
index 000000000..787618ad5
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServices.java
@@ -0,0 +1,216 @@
+/* java.beans.beancontext.BeanContextServices
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.util.Iterator;
+import java.util.TooManyListenersException;
+
+/**
+ * Allows a <code>BeanContext</code> to provide services to its children.
+ *
+ * @specnote it is unclear whether a <code>BeanContextServices</code>
+ * should delegate unhandled requests to parents. I assume so.
+ * @author John Keiser
+ * @since 1.2
+ */
+
+public interface BeanContextServices
+ extends BeanContext, BeanContextServicesListener
+{
+ /**
+ * Register a service to make it available to others.
+ * This class may refuse to add the service based on whatever
+ * information it can gather, including whether the service
+ * provider is trusted.
+ *
+ * @param serviceClass the service class.
+ * @param provider the factory that will actually provide the service.
+ * @return whether the service was added or not.
+ */
+ boolean addService (Class serviceClass,
+ BeanContextServiceProvider provider);
+
+ /**
+ * Make it so that no one else can use this service.
+ * <P>
+ *
+ * If <code>revokeNow</code> is <code>false</code>, the only
+ * effect of this method is to make all subsequent calls to
+ * <code>getService()</code> on this service class fail.
+ * <P>
+ *
+ * If it is <code>true</code>, a message is also sent out to all
+ * listeners on the service and all references to it are released.
+ *
+ * @param serviceClass the service class to revoke.
+ * @param provider the service provider providing the service class.
+ * @param revokeNow whether to release all current references to
+ * the service.
+ */
+ void revokeService (Class serviceClass,
+ BeanContextServiceProvider provider,
+ boolean revokeNow);
+
+ /**
+ * Release your copy of this service.
+ * <P>
+ *
+ * If all copies of the service's class have been relinquished by
+ * the requestor, the <code>BeanContextServiceRevokedListener</code>
+ * previously registered by <code>getService()</code> will be
+ * unregistered.
+ *
+ * @param requestorChild the original <code>BeanContextChild</code>
+ * requesting the service.
+ * @param requestor the original requestor of the service.
+ * @param service the service to relinquish
+ * @see #getService(java.beans.beancontext.BeanContextChild,java.lang.Object,java.lang.Class,java.lang.Object,java.beans.beancontext.BeanContextServiceRevokedListener)
+ */
+ void releaseService (BeanContextChild requestorChild, Object requestor,
+ Object service);
+
+ /**
+ * Get a service from this <code>BeanContextServices</code>.
+ * <P>
+ *
+ * The specified listener will be registered to receive a
+ * revocation notice for the specified serviceClass. One
+ * notification per service class per requestor object will be
+ * sent.
+ * <P>
+ *
+ * The listener will be unregistered when all services that were
+ * obtained by that requestor for that service class are released.
+ * <P>
+ *
+ * If the requested service class is not available, or if this
+ * <code>BeanContextServices</code> object chooses not honor the
+ * request because the service class has been revoked or for some
+ * other reason, then this method will return <code>null</code>.
+ * <P>
+ *
+ * This method may throw unchecked exceptions, so watch out.
+ *
+ * @specnote it is not specified what happens when two subsequent
+ * calls are made to <code>getService()</code> with the
+ * same requestor object and service class but different
+ * listeners. Which listener is to be notified?
+ *
+ * @param requestorChild the <code>BeanContextChild</code>
+ * associated with the requestor. Typically this will be
+ * the same as the requestor itself, but since any
+ * <code>Object</code>, even one outside the hierarchy, may
+ * make a request, this parameter is necessary. Only weak
+ * references to this will be retained, and it will never
+ * be changed, only queried in a read-only manner.
+ * @param requestor the actual requestor of the service. Only
+ * weak references to this will be retained, and it will
+ * never be changed, only queried in a read-only manner.
+ * @param serviceClass the <code>Class</code> of the service being
+ * requested.
+ * @param serviceSelector a parameter to customize the service
+ * returned with.
+ * @param listener a listener that will be notified if the service
+ * being requested is revoked.
+ * @return an instance of <code>serviceClass</code> (such that
+ * <code>instanceof</code> serviceClass is true), or
+ * <code>null</code>.
+ */
+ Object getService (BeanContextChild requestorChild, Object requestor,
+ Class serviceClass, Object serviceSelector,
+ BeanContextServiceRevokedListener listener)
+ throws TooManyListenersException;
+
+ /**
+ * Get a list of all service classes supported.
+ * <P>
+ *
+ * This method must synchronize on
+ * <code>BeanContext.globalHierarchyLock</code>.
+ *
+ * @return a list of all service classes supported.
+ * @see java.beans.beancontext.BeanContext#globalHierarchyLock
+ */
+ Iterator getCurrentServiceClasses ();
+
+ /**
+ * Get a list of valid service selectors for the specified service class.
+ * <P>
+ *
+ * If the specified service class does not have a finite number of
+ * valid service selectors, it should return <code>null</code>.
+ * If it takes a general <code>Integer</code> parameter, for
+ * example, you may as well return <code>null</code> or the poor
+ * soul who called this method will be iterating all day.
+ * <P>
+ *
+ * If it has no valid service selectors, it should still return an empty
+ * <code>Iterator</code>.
+ *
+ * @param serviceClass the service class to get selectors for.
+ * @return a list of valid service selectors for the service
+ * class, or <code>null</code>.
+ */
+ Iterator getCurrentServiceSelectors (Class serviceClass);
+
+ /**
+ * Tell whether the specified service class is available.
+ * Iff getService() could return a non-null value for the
+ * specified service, this method will return <code>true</code>.
+ *
+ * @param serviceClass the service class to check on.
+ * @return whether the specified service class is available.
+ */
+ boolean hasService (Class serviceClass);
+
+ /**
+ * Add a listener on all adds and removes of services.
+ * @param listener the listener to add.
+ */
+ void addBeanContextServicesListener (BeanContextServicesListener listener);
+
+ /**
+ * Remove a listener on all adds and removes of services.
+ * @specnote it is not certain whether this should remove this
+ * listener if it was specified in
+ * <code>getService()</code>.
+ * @param listener the listener to add.
+ */
+ void removeBeanContextServicesListener (BeanContextServicesListener listener);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java b/libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java
new file mode 100644
index 000000000..2081080dd
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java
@@ -0,0 +1,56 @@
+/* java.beans.beancontext.BeanContextServicesListener
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+/**
+ * Listens for service add and revoke events.
+ *
+ * @author John Keiser
+ * @since JDK1.2
+ */
+
+public interface BeanContextServicesListener extends BeanContextServiceRevokedListener {
+ /**
+ * Called by <code>BeanContextServices</code> whenever a service is made available.
+ *
+ * @param event the service revoked event, with useful information
+ * about the new service.
+ */
+ void serviceAvailable(BeanContextServiceAvailableEvent event);
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java
new file mode 100644
index 000000000..30b4a6fbd
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java
@@ -0,0 +1,896 @@
+/* BeanContextServicesSupport.java --
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TooManyListenersException;
+
+/**
+ * This is a helper class for implementing a bean context which
+ * supplies services. It is intended to be used either by
+ * subclassing or by calling methods of this implementation
+ * from another.
+ *
+ * @author Michael Koch
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.2
+ */
+public class BeanContextServicesSupport
+ extends BeanContextSupport
+ implements BeanContextServices
+{
+ private static final long serialVersionUID = -8494482757288719206L;
+
+ protected class BCSSChild
+ extends BeanContextSupport.BCSChild
+ {
+ private static final long serialVersionUID = -3263851306889194873L;
+
+ BCSSChild(Object targetChild, Object peer)
+ {
+ super(targetChild, peer);
+ }
+ }
+
+ protected class BCSSProxyServiceProvider
+ implements BeanContextServiceProvider,
+ BeanContextServiceRevokedListener
+ {
+ private static final long serialVersionUID = 7078212910685744490L;
+
+ private BeanContextServiceProvider provider;
+
+ BCSSProxyServiceProvider(BeanContextServiceProvider p)
+ {
+ provider = p;
+ }
+
+ public Iterator getCurrentServiceSelectors (BeanContextServices bcs,
+ Class serviceClass)
+ {
+ return provider.getCurrentServiceSelectors(bcs, serviceClass);
+ }
+
+ public Object getService (BeanContextServices bcs,
+ Object requestor,
+ Class serviceClass,
+ Object serviceSelector)
+ {
+ return provider.getService(bcs, requestor, serviceClass,
+ serviceSelector);
+ }
+
+ public void releaseService (BeanContextServices bcs,
+ Object requestor,
+ Object service)
+ {
+ provider.releaseService(bcs, requestor, service);
+ }
+
+ public void serviceRevoked (BeanContextServiceRevokedEvent bcsre)
+ {
+ if (provider instanceof BeanContextServiceRevokedListener)
+ ((BeanContextServiceRevokedListener) provider).serviceRevoked(bcsre);
+ }
+ }
+
+ protected static class BCSSServiceProvider
+ implements Serializable
+ {
+ private static final long serialVersionUID = 861278251667444782L;
+
+ protected BeanContextServiceProvider serviceProvider;
+
+ private Class serviceClass;
+
+ private BCSSServiceProvider(Class serviceClass,
+ BeanContextServiceProvider provider)
+ {
+ this.serviceClass = serviceClass;
+ serviceProvider = provider;
+ }
+
+ protected BeanContextServiceProvider getServiceProvider()
+ {
+ return serviceProvider;
+ }
+
+ private Class getServiceClass()
+ {
+ return serviceClass;
+ }
+
+ }
+
+ /**
+ * Represents a request for a service. This is
+ * a common superclass used by the classes which maintain
+ * the listener-requestor and service-requestor relationships.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+ private static abstract class Request
+ {
+ private Object requestor;
+
+ public Request(Object requestor)
+ {
+ this.requestor = requestor;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof Request)
+ {
+ Request req = (Request) obj;
+ return req.getRequestor().equals(requestor);
+ }
+ return false;
+ }
+
+ public Object getRequestor()
+ {
+ return requestor;
+ }
+
+ }
+
+ /**
+ * Represents a relationship between a service requestor
+ * and a revocation listener.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+ private static class ServiceRequest
+ extends Request
+ {
+
+ private BeanContextServiceRevokedListener listener;
+
+ public ServiceRequest(Object requestor,
+ BeanContextServiceRevokedListener listener)
+ {
+ super(requestor);
+ this.listener = listener;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof ServiceRequest)
+ {
+ ServiceRequest sr = (ServiceRequest) obj;
+ return (super.equals(obj) &&
+ sr.getListener().equals(listener));
+ }
+ return false;
+ }
+
+ public BeanContextServiceRevokedListener getListener()
+ {
+ return listener;
+ }
+ }
+
+ /**
+ * Represents a relationship between a service requestor
+ * and a service instance.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+ private static class ServiceLease
+ extends Request
+ {
+
+ private Object service;
+
+ public ServiceLease(Object requestor, Object service)
+ {
+ super(requestor);
+ this.service = service;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof ServiceLease)
+ {
+ ServiceLease sl = (ServiceLease) obj;
+ return (super.equals(obj) &&
+ sl.getService().equals(service));
+ }
+ return false;
+ }
+
+ public Object getService()
+ {
+ return service;
+ }
+ }
+
+ /**
+ * A collection of listeners who receive availability
+ * and revocation notifications.
+ */
+ protected transient ArrayList bcsListeners;
+
+ protected transient BCSSProxyServiceProvider proxy;
+
+ /**
+ * The number of serializable service providers.
+ */
+ protected transient int serializable;
+
+ /**
+ * A map of registered services, linking the service
+ * class to its associated {@link BCSSServiceProvider}.
+ */
+ protected transient HashMap services;
+
+ /**
+ * A map of children to a list of services they
+ * have obtained.
+ */
+ private transient HashMap serviceUsers;
+
+ /**
+ * A map of services to {@link ServiceRequest}s.
+ */
+ private transient HashMap serviceRequests;
+
+ /**
+ * A map of {@link ServiceLease}s to providers.
+ */
+ private transient HashMap serviceLeases;
+
+ /**
+ * Construct a {@link BeanContextServicesSupport} instance.
+ */
+ public BeanContextServicesSupport ()
+ {
+ super();
+ }
+
+ /**
+ * Construct a {@link BeanContextServicesSupport} instance.
+ *
+ * @param peer the bean context services peer (<code>null</code> permitted).
+ */
+ public BeanContextServicesSupport (BeanContextServices peer)
+ {
+ super(peer);
+ }
+
+ /**
+ * Construct a {@link BeanContextServicesSupport} instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ * @param locale the locale (<code>null</code> permitted, equivalent to
+ * the default locale).
+ */
+ public BeanContextServicesSupport(BeanContextServices peer, Locale locale)
+ {
+ super(peer, locale);
+ }
+
+ /**
+ * Construct a {@link BeanContextServicesSupport} instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ * @param locale the locale (<code>null</code> permitted, equivalent to
+ * the default locale).
+ * @param dtime a flag indicating whether or not the bean context is in
+ * design time mode.
+ */
+ public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
+ boolean dtime)
+ {
+ super(peer, locale, dtime);
+ }
+
+ /**
+ * Construct a {@link BeanContextServicesSupport} instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ * @param locale the locale (<code>null</code> permitted, equivalent to
+ * the default locale).
+ * @param dtime a flag indicating whether or not the bean context is in
+ * design time mode.
+ * @param visible initial value of the <code>okToUseGui</code> flag.
+ */
+ public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
+ boolean dtime, boolean visible)
+ {
+ super(peer, locale, dtime, visible);
+ }
+
+ /**
+ * Adds a new listener for service availability and
+ * revocation events.
+ *
+ * @param listener the listener to add.
+ */
+ public void addBeanContextServicesListener
+ (BeanContextServicesListener listener)
+ {
+ synchronized (bcsListeners)
+ {
+ if (! bcsListeners.contains(listener))
+ bcsListeners.add(listener);
+ }
+ }
+
+ /**
+ * Registers a new service from the specified service provider.
+ * The service is internally associated with the service provider
+ * and a <code>BeanContextServiceAvailableEvent</code> is fired. If
+ * the service is already registered, then this method instead
+ * returns <code>false</code>. This is equivalent to calling
+ * <code>addService(serviceClass, bcsp, true)</code>.
+ *
+ * @param serviceClass the class of the service to be registered.
+ * @param bcsp the provider of the given service.
+ * @return true if the service was registered successfully.
+ * @see #addService(Class, BeanContextServiceProvider, boolean)
+ */
+ public boolean addService (Class serviceClass,
+ BeanContextServiceProvider bcsp)
+ {
+ return addService(serviceClass, bcsp, true);
+ }
+
+ /**
+ * Registers a new service from the specified service provider.
+ * The service is internally associated with the service provider
+ * and (if <code>fireEvent</code> is true) a
+ * <code>BeanContextServiceAvailableEvent</code> is fired. If
+ * the service is already registered, then this method instead
+ * returns <code>false</code>.
+ *
+ * @param serviceClass the class of the service to be registered.
+ * @param bcsp the provider of the given service.
+ * @param fireEvent true if a service availability event should
+ * be fired.
+ * @return true if the service was registered successfully.
+ */
+ protected boolean addService (Class serviceClass,
+ BeanContextServiceProvider bcsp,
+ boolean fireEvent)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ if (services.containsKey(serviceClass))
+ return false;
+ services.put(serviceClass,
+ createBCSSServiceProvider(serviceClass, bcsp));
+ if (bcsp instanceof Serializable)
+ ++serializable;
+ if (fireEvent)
+ fireServiceAdded(serviceClass);
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Deserializes any service providers which are serializable. This
+ * method is called by the <code>readObject</code> method of
+ * {@link BeanContextSupport} prior to deserialization of the children.
+ * Subclasses may envelope its behaviour in order to read further
+ * serialized data to the stream.
+ *
+ * @param ois the stream from which data is being deserialized.
+ * @throws IOException if an I/O error occurs.
+ * @throws ClassNotFoundException if the class of a deserialized object
+ * can not be found.
+ */
+ protected void bcsPreDeserializationHook (ObjectInputStream ois)
+ throws ClassNotFoundException, IOException
+ {
+ serializable = ois.readInt();
+ for (int a = 0; a < serializable; ++a)
+ {
+ BCSSServiceProvider bcsssp = (BCSSServiceProvider) ois.readObject();
+ addService(bcsssp.getServiceClass(), bcsssp.getServiceProvider());
+ }
+ }
+
+ /**
+ * Serializes any service providers which are serializable. This
+ * method is called by the <code>writeObject</code> method of
+ * {@link BeanContextSupport} prior to serialization of the children.
+ * Subclasses may envelope its behaviour in order to add further
+ * serialized data to the stream.
+ *
+ * @param oos the stream to which data is being serialized.
+ * @throws IOException if an I/O error occurs.
+ */
+ protected void bcsPreSerializationHook (ObjectOutputStream oos)
+ throws IOException
+ {
+ oos.writeInt(serializable);
+ synchronized (services)
+ {
+ Iterator i = services.values().iterator();
+ while (i.hasNext())
+ {
+ BCSSServiceProvider bcsssp = (BCSSServiceProvider) i.next();
+ if (bcsssp.getServiceProvider() instanceof Serializable)
+ oos.writeObject(bcsssp);
+ }
+ }
+ }
+
+ /**
+ * Revokes any services used by a child that has just been removed.
+ * The superclass ({@link BeanContextSupport}) calls this method
+ * when a child has just been successfully removed. Subclasses can
+ * extend this method in order to perform additional operations
+ * on child removal.
+ *
+ * @param child the child being removed.
+ * @param bcsc the support object for the child.
+ */
+ protected void childJustRemovedHook (Object child,
+ BeanContextSupport.BCSChild bcsc)
+ {
+ if (child instanceof BeanContextChild)
+ {
+ BeanContextChild bcchild = (BeanContextChild) child;
+ Iterator childServices = ((List) serviceUsers.get(bcchild)).iterator();
+ while (childServices.hasNext())
+ releaseService(bcchild, this, childServices.next());
+ serviceUsers.remove(bcchild);
+ }
+ }
+
+ /**
+ * Overrides the {@link BeanContextSupport#createBCSChild} method
+ * so as to use a {@link BCSSChild} instead.
+ *
+ * @param targetChild the child to create the child for.
+ * @param peer the peer which relates to the child if a proxy is used.
+ * @return a new instance of {@link BCSSChild}.
+ */
+ protected BeanContextSupport.BCSChild createBCSChild (Object targetChild,
+ Object peer)
+ {
+ return new BCSSChild(targetChild, peer);
+ }
+
+ /**
+ * Provides a hook so that subclasses can replace the
+ * {@link BCSSServiceProvider} class, used to store registered
+ * service providers, with a subclass without replacing the
+ * {@link #addService(Class, BeanContextServiceProvider)} method.
+ *
+ * @param sc the class of service being registered.
+ * @param bcsp the provider of the service.
+ * @return a instance of {@link BCSSServiceProvider} wrapping the provider.
+ */
+ protected BeanContextServicesSupport.BCSSServiceProvider
+ createBCSSServiceProvider (Class sc, BeanContextServiceProvider bcsp)
+ {
+ return new BCSSServiceProvider(sc, bcsp);
+ }
+
+ /**
+ * Sends a <code>BeanContextServiceAvailableEvent</code> to all
+ * registered listeners.
+ *
+ * @param bcssae the event to send.
+ */
+ protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae)
+ {
+ synchronized (bcsListeners)
+ {
+ int size = bcsListeners.size();
+ for (int i = 0; i < size; ++i)
+ {
+ BeanContextServicesListener bcsl
+ = (BeanContextServicesListener) bcsListeners.get(i);
+ bcsl.serviceAvailable(bcssae);
+ }
+ }
+ }
+
+ /**
+ * Sends a <code>BeanContextServiceAvailableEvent</code> to all
+ * registered listeners.
+ *
+ * @param serviceClass the service that is now available.
+ * @see #fireServiceAdded(BeanContextServiceAvailableEvent)
+ */
+ protected final void fireServiceAdded (Class serviceClass)
+ {
+ fireServiceAdded(new BeanContextServiceAvailableEvent(this,
+ serviceClass));
+ }
+
+ /**
+ * Sends a <code>BeanContextServiceRevokedEvent</code> to all
+ * registered listeners.
+ *
+ * @param event the event to send.
+ */
+ protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event)
+ {
+ synchronized (bcsListeners)
+ {
+ int size = bcsListeners.size();
+ for (int i = 0; i < size; ++i)
+ {
+ BeanContextServicesListener bcsl
+ = (BeanContextServicesListener) bcsListeners.get(i);
+ bcsl.serviceRevoked(event);
+ }
+ List requests = (List) serviceRequests.get(event.getServiceClass());
+ if (requests != null)
+ {
+ Iterator i = requests.iterator();
+ while (i.hasNext())
+ {
+ ServiceRequest r = (ServiceRequest) i.next();
+ r.getListener().serviceRevoked(event);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends a <code>BeanContextServiceRevokedEvent</code> to all
+ * registered listeners.
+ *
+ * @param serviceClass the service that has been revoked.
+ * @see #fireServiceRevoked(BeanContextServiceRevokedEvent)
+ */
+ protected final void fireServiceRevoked (Class serviceClass,
+ boolean revokeNow)
+ {
+ fireServiceRevoked(new BeanContextServiceRevokedEvent(this, serviceClass,
+ revokeNow));
+ }
+
+ /**
+ * Returns the services peer given at construction time,
+ * or <code>null</code> if no peer was given.
+ *
+ * @return the {@link BeanContextServices} peer.
+ */
+ public BeanContextServices getBeanContextServicesPeer ()
+ {
+ return (BeanContextServices) beanContextChildPeer;
+ }
+
+ /**
+ * Returns <code>child</code> as an instance of
+ * {@link BeanContextServicesListener}, or <code>null</code> if
+ * <code>child</code> does not implement that interface.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The child cast to {@link BeanContextServicesListener}.
+ */
+ protected static final BeanContextServicesListener
+ getChildBeanContextServicesListener(Object child)
+ {
+ if (child instanceof BeanContextServicesListener)
+ return (BeanContextServicesListener) child;
+ else
+ return null;
+ }
+
+ /**
+ * Returns an iterator over the currently available
+ * services.
+ *
+ * @return an iterator over the currently available services.
+ */
+ public Iterator getCurrentServiceClasses ()
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ return services.keySet().iterator();
+ }
+ }
+ }
+
+ /**
+ * Returns an iterator over the service selectors of the service
+ * provider for the given service. The iterator is actually
+ * obtained by calling the
+ * {@link BeanContextServiceProvider#getCurrentServiceSelectors}
+ * of the provider itself. If the specified service is not available,
+ * <code>null</code> is returned.
+ *
+ * @param serviceClass the service whose provider's selectors should
+ * be iterated over.
+ * @return an {@link Iterator} over the service selectors of the
+ * provider of the given service.
+ */
+ public Iterator getCurrentServiceSelectors (Class serviceClass)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ BeanContextServiceProvider bcsp
+ = ((BCSSServiceProvider)
+ services.get(serviceClass)).getServiceProvider();
+ if (bcsp == null)
+ return null;
+ else
+ return bcsp.getCurrentServiceSelectors(this, serviceClass);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the specified service. If a provider for the service
+ * is registered in this context, then the request is passed on to
+ * the provider and the service returned. Otherwise, the request
+ * is delegated to a parent {@link BeanContextServices}, if possible.
+ * If the service can not be found at all, then <code>null</code>
+ * is returned.
+ *
+ * @param child the child obtaining the reference.
+ * @param requestor the requestor of the service, which may be the
+ * child itself.
+ * @param serviceClass the service being requested.
+ * @param serviceSelector an additional service-dependent parameter
+ * (may be <code>null</code> if not appropriate).
+ * @param bcsrl a listener used to notify the requestor that the service
+ * has since been revoked.
+ * @return a reference to the service requested, or <code>null</code>.
+ * @throws TooManyListenersException according to Sun's documentation.
+ */
+ public Object getService (BeanContextChild child, Object requestor,
+ Class serviceClass, Object serviceSelector,
+ BeanContextServiceRevokedListener bcsrl)
+ throws TooManyListenersException
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ Object service;
+ BeanContextServiceProvider provider = ((BCSSServiceProvider)
+ services.get(serviceClass)).getServiceProvider();
+ if (provider != null)
+ {
+ service = provider.getService(this, requestor, serviceClass,
+ serviceSelector);
+ List childServices = (List) serviceUsers.get(child);
+ if (childServices == null)
+ {
+ childServices = new ArrayList();
+ serviceUsers.put(child, childServices);
+ }
+ childServices.add(serviceClass);
+ }
+ else
+ {
+ BeanContextServices peer = getBeanContextServicesPeer();
+ if (peer != null)
+ service = peer.getService(child, requestor, serviceClass,
+ serviceSelector, bcsrl);
+ else
+ service = null;
+ }
+ if (service != null)
+ {
+ ServiceRequest request = new ServiceRequest(requestor, bcsrl);
+ Set requests = (Set) serviceRequests.get(serviceClass);
+ if (requests == null)
+ {
+ requests = new HashSet();
+ serviceRequests.put(serviceClass, requests);
+ }
+ requests.add(request);
+ ServiceLease lease = new ServiceLease(requestor, service);
+ serviceLeases.put(lease, provider);
+ }
+ return service;
+ }
+ }
+ }
+
+ /**
+ * Returns true if the specified service is available.
+ *
+ * @param serviceClass the service to check for.
+ * @return true if the service is available.
+ */
+ public boolean hasService (Class serviceClass)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ return services.containsKey(serviceClass);
+ }
+ }
+ }
+
+ public void initialize ()
+ {
+ super.initialize();
+
+ bcsListeners = new ArrayList();
+ services = new HashMap();
+ serviceUsers = new HashMap();
+ serviceRequests = new HashMap();
+ serviceLeases = new HashMap();
+ }
+
+ /**
+ * Subclasses may override this method to allocate resources
+ * from the nesting bean context.
+ */
+ protected void initializeBeanContextResources()
+ {
+ /* Purposefully left empty */
+ }
+
+ /**
+ * Relinquishes any resources obtained from the parent context.
+ * Specifically, those services obtained from the parent are revoked.
+ * Subclasses may override this method to deallocate resources
+ * from the nesting bean context.
+ */
+ protected void releaseBeanContextResources()
+ {
+ /* Purposefully left empty */
+ }
+
+ /**
+ * Releases the reference to a service held by a
+ * {@link BeanContextChild} (or an arbitrary object associated
+ * with it). It simply calls the appropriate method on the
+ * underlying provider.
+ *
+ * @param child the child who holds the reference.
+ * @param requestor the object that requested the reference.
+ * @param service the service being released.
+ */
+ public void releaseService (BeanContextChild child, Object requestor,
+ Object service)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ ServiceLease lease = new ServiceLease(requestor, service);
+ BeanContextServiceProvider provider = (BeanContextServiceProvider)
+ serviceLeases.get(lease);
+ if (provider != null)
+ provider.releaseService(this, requestor, service);
+ else
+ {
+ BeanContextServices peer = getBeanContextServicesPeer();
+ if (peer != null)
+ peer.releaseService(child, requestor, service);
+ }
+ serviceLeases.remove(lease);
+ }
+ }
+ }
+
+ public void removeBeanContextServicesListener
+ (BeanContextServicesListener listener)
+ {
+ synchronized (bcsListeners)
+ {
+ bcsListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Revokes the given service. A {@link BeanContextServiceRevokedEvent} is
+ * emitted to all registered {@link BeanContextServiceRevokedListener}s
+ * and {@link BeanContextServiceListener}s. If <code>revokeCurrentServicesNow</code>
+ * is true, termination of the service is immediate. Otherwise, prior
+ * acquisitions of the service by requestors remain valid.
+ *
+ * @param serviceClass the service to revoke.
+ * @param bcsp the provider of the revoked service.
+ * @param revokeCurrentServicesNow true if this is an exceptional circumstance
+ * where service should be immediately revoked.
+ */
+ public void revokeService (Class serviceClass, BeanContextServiceProvider bcsp,
+ boolean revokeCurrentServicesNow)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (services)
+ {
+ fireServiceRevoked(serviceClass, revokeCurrentServicesNow);
+ services.remove(serviceClass);
+ if (bcsp instanceof Serializable)
+ --serializable;
+ }
+ }
+ }
+
+ public void serviceAvailable (BeanContextServiceAvailableEvent bcssae)
+ {
+ synchronized (services)
+ {
+ Class klass = bcssae.getServiceClass();
+ if (services.containsKey(klass))
+ return;
+ Iterator it = bcsChildren();
+ while (it.hasNext())
+ {
+ Object obj = it.next();
+ if (obj instanceof BeanContextServices)
+ ((BeanContextServices) obj).serviceAvailable(bcssae);
+ }
+ }
+ }
+
+ public void serviceRevoked (BeanContextServiceRevokedEvent bcssre)
+ {
+ synchronized (services)
+ {
+ Class klass = bcssre.getServiceClass();
+ if (services.containsKey(klass))
+ return;
+ Iterator it = bcsChildren();
+ while (it.hasNext())
+ {
+ Object obj = it.next();
+ if (obj instanceof BeanContextServices)
+ ((BeanContextServices) obj).serviceRevoked(bcssre);
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/java/beans/beancontext/BeanContextSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextSupport.java
new file mode 100644
index 000000000..fdae387d4
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/BeanContextSupport.java
@@ -0,0 +1,1079 @@
+/* BeanContextSupport.java --
+ Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans.beancontext;
+
+import java.beans.Beans;
+import java.beans.DesignMode;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+import java.beans.Visibility;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * This is a helper class for implementing a bean context. It is
+ * intended to be used either by subclassing or by calling methods
+ * of this implementation from another.
+ *
+ * @author Michael Koch
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.2
+ */
+public class BeanContextSupport extends BeanContextChildSupport
+ implements BeanContext, Serializable, PropertyChangeListener,
+ VetoableChangeListener
+{
+ private static final long serialVersionUID = -4879613978649577204L;
+
+ /**
+ * Deserializes a stored bean context. Hook methods are provided to allow
+ * subclasses to perform their own deserialization after the default
+ * deserialization but prior to the deserialization of the children. Note that
+ * {@link #readChildren(ObjectInputStream)} is only called if there
+ * is no distinct peer. If there is, the peer is expected to call
+ * the method instead.
+ *
+ * @param s the stream to deserialize.
+ * @throws ClassNotFoundException if the class of an object being deserialized
+ * could not be found.
+ * @throws IOException if an I/O error occurs.
+ */
+ private void readObject (ObjectInputStream s)
+ throws ClassNotFoundException, IOException
+ {
+ s.defaultReadObject();
+ bcsPreDeserializationHook(s);
+ BeanContext peer = getBeanContextPeer();
+ if (peer == null || peer == this)
+ readChildren(s);
+ }
+
+ /**
+ * Serializes a bean context. Hook methods are provided to allow
+ * subclasses to perform their own serialization after the default
+ * serialization but prior to serialization of the children. Note that
+ * {@link #writeChildren(ObjectOutputStream)} is only called if there
+ * is no distinct peer. If there is, the peer is expected to call
+ * the method instead.
+ *
+ * @param s the stream to serialize.
+ * @throws ClassNotFoundException if the class of an object being deserialized
+ * could not be found.
+ * @throws IOException if an I/O error occurs.
+ */
+ private void writeObject (ObjectOutputStream s)
+ throws ClassNotFoundException, IOException
+ {
+ serializing = true;
+ s.defaultWriteObject();
+ bcsPreSerializationHook(s);
+ BeanContext peer = getBeanContextPeer();
+ if (peer == null || peer == this)
+ writeChildren(s);
+ serializing = false;
+ }
+
+ protected class BCSChild implements Serializable
+ {
+ private static final long serialVersionUID = -5815286101609939109L;
+
+ private Object targetChild;
+ private Object peer;
+
+ BCSChild(Object targetChild, Object peer)
+ {
+ this.targetChild = targetChild;
+ this.peer = peer;
+ }
+
+ private Object getTargetChild()
+ {
+ return targetChild;
+ }
+
+ }
+
+ protected static final class BCSIterator implements Iterator
+ {
+ private Iterator child;
+
+ BCSIterator(Iterator child)
+ {
+ this.child = child;
+ }
+
+ public boolean hasNext ()
+ {
+ return child.hasNext();
+ }
+
+ public Object next ()
+ {
+ return child.next();
+ }
+
+ public void remove ()
+ {
+ // This must be a noop remove operation.
+ }
+ }
+
+ protected transient ArrayList bcmListeners;
+
+ protected transient HashMap children;
+
+ protected transient boolean designTime;
+
+ protected transient Locale locale;
+
+ protected transient boolean okToUseGui;
+
+ private transient boolean serializing;
+
+ /**
+ * Construct a BeanContextSupport instance.
+ */
+ public BeanContextSupport ()
+ {
+ this (null, null, false, true);
+ }
+
+ /**
+ * Construct a BeanContextSupport instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ */
+ public BeanContextSupport(BeanContext peer)
+ {
+ this (peer, null, false, true);
+ }
+
+ /**
+ * Construct a BeanContextSupport instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ * @param locale the locale (<code>null</code> permitted, equivalent to
+ * the default locale).
+ */
+ public BeanContextSupport (BeanContext peer, Locale locale)
+ {
+ this (peer, locale, false, true);
+ }
+
+ /**
+ * Construct a BeanContextSupport instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ * @param locale the locale (<code>null</code> permitted, equivalent to
+ * the default locale).
+ * @param dtime a flag indicating whether or not the bean context is in
+ * design time mode.
+ */
+ public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime)
+ {
+ this (peer, locale, dtime, true);
+ }
+
+ /**
+ * Construct a BeanContextSupport instance.
+ *
+ * @param peer the bean context peer (<code>null</code> permitted).
+ * @param locale the locale (<code>null</code> permitted, equivalent to
+ * the default locale).
+ * @param dtime a flag indicating whether or not the bean context is in
+ * design time mode.
+ * @param visible initial value of the <code>okToUseGui</code> flag.
+ */
+ public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime,
+ boolean visible)
+ {
+ super(peer);
+
+ this.locale = locale == null ? Locale.getDefault() : locale;
+ designTime = dtime;
+ okToUseGui = visible;
+
+ initialize ();
+ }
+
+ /**
+ * <p>
+ * Add a child to the bean context. A child can be a simple
+ * <code>Object</code>, a <code>BeanContextChild</code>
+ * or another <code>BeanContext</code>.
+ * </p>
+ * <p>
+ * The children of a <code>BeanContext</code> form a set. As
+ * a result, this method returns <code>false</code> if the given
+ * object is already a child of this context.
+ * </p>
+ * <p>
+ * If the child is a <code>BeanContextChild</code>, or a proxy
+ * for such a child, the <code>setBeanContext()</code> method
+ * is invoked on the child. If this operation is vetoed by the
+ * child, via throwing a <code>PropertyVetoException</code>,
+ * then the current completion state of the <code>add()</code>
+ * operation is rolled back and a <code>IllegalStateException</code>
+ * is thrown. If the <code>BeanContextChild</code> is successfully
+ * added, then the context registers with its
+ * <code>PropertyChangeListener</code> and
+ * <code>VetoableChangeListener</code> for "beanContext" events.
+ * </p>
+ * <p>
+ * If the child implements <code>java.beans.Visibility</code>,
+ * then its ability to use a GUI is set based on that of
+ * this context.
+ * </p>
+ * <p>
+ * A <code>BeanContextMembershipEvent</code> is fired when the
+ * child is successfully added to the bean context.
+ * </p>
+ * <p>
+ * This method is synchronized over the global hierarchy lock.
+ * </p>
+ *
+ * @param targetChild the child to add.
+ * @return false if the child has already been added.
+ * @throws IllegalArgumentException if the child is null.
+ * @throws IllegalStateException if the child vetos the setting
+ * of its context.
+ */
+ public boolean add(Object targetChild)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ if (targetChild == null)
+ throw new IllegalArgumentException();
+
+ BCSChild child;
+ synchronized (children)
+ {
+ if (children.containsKey(targetChild)
+ || ! validatePendingAdd(targetChild))
+ return false;
+ child = createBCSChild(targetChild, beanContextChildPeer);
+ children.put(targetChild, child);
+ }
+ synchronized (targetChild)
+ {
+ BeanContextChild bcChild = null;
+ if (targetChild instanceof BeanContextChild)
+ bcChild = (BeanContextChild) targetChild;
+ if (targetChild instanceof BeanContextProxy)
+ bcChild = ((BeanContextProxy) targetChild).getBeanContextProxy();
+ if (bcChild != null)
+ try
+ {
+ bcChild.setBeanContext(this);
+ bcChild.addVetoableChangeListener("beanContext", this);
+ bcChild.addPropertyChangeListener("beanContext", this);
+ }
+ catch (PropertyVetoException e)
+ {
+ synchronized (children)
+ {
+ children.remove(targetChild);
+ }
+ throw new IllegalStateException("The child refused to " +
+ "associate itself with " +
+ "this context.", e);
+ }
+ if (targetChild instanceof Visibility)
+ {
+ Visibility visibleChild = (Visibility) targetChild;
+ if (okToUseGui)
+ visibleChild.okToUseGui();
+ else
+ visibleChild.dontUseGui();
+ }
+ childJustAddedHook(targetChild, child);
+ }
+ fireChildrenAdded(new BeanContextMembershipEvent(this,
+ new Object[]{ targetChild }));
+ return true;
+ }
+ }
+
+ public boolean addAll (Collection c)
+ {
+ // Intentionally throws an exception.
+ throw new UnsupportedOperationException();
+ }
+
+ public void addBeanContextMembershipListener
+ (BeanContextMembershipListener listener)
+ {
+ synchronized (bcmListeners)
+ {
+ if (! bcmListeners.contains(listener))
+ bcmListeners.add(listener);
+ }
+ }
+
+ /**
+ * Returns true if this bean needs a GUI
+ * but is being prevented from using one.
+ *
+ * @return true if <code>needsGui()</code>
+ * is true but the bean has been
+ * told not to use it.
+ */
+ public boolean avoidingGui()
+ {
+ return needsGui() && (!okToUseGui);
+ }
+
+ protected Iterator bcsChildren ()
+ {
+ synchronized (children)
+ {
+ return new BCSIterator(children.values().iterator());
+ }
+ }
+
+ /**
+ * Subclasses may use this method to perform their own deserialization
+ * after the default deserialization process has taken place, but
+ * prior to the deserialization of the children. It should not
+ * be used to replace the implementation of <code>readObject</code>
+ * in the subclass.
+ *
+ * @param ois the input stream.
+ * @throws ClassNotFoundException if the class of an object being deserialized
+ * could not be found.
+ * @throws IOException if an I/O error occurs.
+ */
+ protected void bcsPreDeserializationHook (ObjectInputStream ois)
+ throws ClassNotFoundException, IOException
+ {
+ /* Purposefully left empty */
+ }
+
+ /**
+ * Subclasses may use this method to perform their own serialization
+ * after the default serialization process has taken place, but
+ * prior to the serialization of the children. It should not
+ * be used to replace the implementation of <code>writeObject</code>
+ * in the subclass.
+ *
+ * @param oos the output stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ protected void bcsPreSerializationHook (ObjectOutputStream oos)
+ throws IOException
+ {
+ /* Purposefully left empty */
+ }
+
+ /**
+ * Called when a child is deserialized.
+ *
+ * @param child the deserialized child.
+ * @param bcsc the deserialized context wrapper for the child.
+ */
+ protected void childDeserializedHook (Object child, BeanContextSupport.BCSChild bcsc)
+ {
+ // Do nothing in the base class.
+ }
+
+ protected void childJustAddedHook (Object child, BeanContextSupport.BCSChild bcsc)
+ {
+ // Do nothing in the base class.
+ }
+
+ protected void childJustRemovedHook (Object child, BeanContextSupport.BCSChild bcsc)
+ {
+ // Do nothing in the base class.
+ }
+
+ protected static final boolean classEquals (Class first, Class second)
+ {
+ // Lame function!
+ return (first == second || first.getName().equals(second.getName()));
+ }
+
+ public void clear ()
+ {
+ // This is the right thing to do.
+ // The JDK docs are really bad here.
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean contains (Object o)
+ {
+ synchronized (children)
+ {
+ return children.containsKey(o);
+ }
+ }
+
+ public boolean containsAll (Collection c)
+ {
+ synchronized (children)
+ {
+ Iterator it = c.iterator();
+ while (it.hasNext())
+ if (! children.containsKey(it.next()))
+ return false;
+ }
+ return true;
+ }
+
+ public boolean containsKey (Object o)
+ {
+ synchronized (children)
+ {
+ return children.containsKey(o);
+ }
+ }
+
+ protected final Object[] copyChildren ()
+ {
+ synchronized (children)
+ {
+ return children.keySet().toArray();
+ }
+ }
+
+ protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, Object peer)
+ {
+ return new BCSChild(targetChild, peer);
+ }
+
+ /**
+ * Deserializes objects (written by {@link #serialize(ObjectOutputStream,
+ * Collection)}) and adds them to the specified collection.
+ *
+ * @param ois the input stream (<code>null</code> not permitted).
+ * @param coll the collection to add the objects to (<code>null</code> not
+ * permitted).
+ *
+ * @throws ClassNotFoundException
+ * @throws IOException
+ *
+ * @see #serialize(ObjectOutputStream, Collection)
+ */
+ protected final void deserialize (ObjectInputStream ois, Collection coll)
+ throws ClassNotFoundException, IOException
+ {
+ int itemCount = ois.readInt();
+ for (int i = 0; i < itemCount; i++)
+ coll.add(ois.readObject());
+ }
+
+ /**
+ * Informs this bean that is should not make
+ * use of the GUI.
+ */
+ public void dontUseGui()
+ {
+ okToUseGui = false;
+ }
+
+ protected final void fireChildrenAdded (BeanContextMembershipEvent bcme)
+ {
+ synchronized (bcmListeners)
+ {
+ Iterator it = bcmListeners.iterator();
+ while (it.hasNext())
+ {
+ BeanContextMembershipListener l
+ = (BeanContextMembershipListener) it.next();
+ l.childrenAdded(bcme);
+ }
+ }
+ }
+
+ protected final void fireChildrenRemoved (BeanContextMembershipEvent bcme)
+ {
+ synchronized (bcmListeners)
+ {
+ Iterator it = bcmListeners.iterator();
+ while (it.hasNext())
+ {
+ BeanContextMembershipListener l
+ = (BeanContextMembershipListener) it.next();
+ l.childrenRemoved(bcme);
+ }
+ }
+ }
+
+ /**
+ * Returns the bean context peer.
+ *
+ * @return The bean context peer.
+ *
+ * @see BeanContextChildSupport#beanContextChildPeer
+ */
+ public BeanContext getBeanContextPeer()
+ {
+ return (BeanContext) beanContextChildPeer;
+ }
+
+ /**
+ * Returns the {@link BeanContextChild} implementation for the given child.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The bean context child.
+ *
+ * @throws IllegalArgumentException if <code>child</code> implements both
+ * the {@link BeanContextChild} and {@link BeanContextProxy} interfaces.
+ */
+ protected static final BeanContextChild getChildBeanContextChild(Object child)
+ {
+ if (child == null)
+ return null;
+ if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
+ throw new IllegalArgumentException("Child cannot implement "
+ + "BeanContextChild and BeanContextProxy simultaneously.");
+ if (child instanceof BeanContextChild)
+ return (BeanContextChild) child;
+ if (child instanceof BeanContextProxy)
+ return ((BeanContextProxy) child).getBeanContextProxy();
+ return null;
+ }
+
+ /**
+ * Returns <code>child</code> as an instance of
+ * {@link BeanContextMembershipListener}, or <code>null</code> if
+ * <code>child</code> does not implement that interface.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The child cast to {@link BeanContextMembershipListener}.
+ */
+ protected static final BeanContextMembershipListener
+ getChildBeanContextMembershipListener(Object child)
+ {
+ if (child instanceof BeanContextMembershipListener)
+ return (BeanContextMembershipListener) child;
+ else
+ return null;
+ }
+
+ /**
+ * Returns <code>child</code> as an instance of
+ * {@link PropertyChangeListener}, or <code>null</code> if <code>child</code>
+ * does not implement that interface.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The child cast to {@link PropertyChangeListener}.
+ */
+ protected static final PropertyChangeListener getChildPropertyChangeListener(
+ Object child)
+ {
+ if (child instanceof PropertyChangeListener)
+ return (PropertyChangeListener) child;
+ else
+ return null;
+ }
+
+ /**
+ * Returns <code>child</code> as an instance of {@link Serializable}, or
+ * <code>null</code> if <code>child</code> does not implement that
+ * interface.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The child cast to {@link Serializable}.
+ */
+ protected static final Serializable getChildSerializable(Object child)
+ {
+ if (child instanceof Serializable)
+ return (Serializable) child;
+ else
+ return null;
+ }
+
+ /**
+ * Returns <code>child</code> as an instance of
+ * {@link VetoableChangeListener}, or <code>null</code> if <code>child</code>
+ * does not implement that interface.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The child cast to {@link VetoableChangeListener}.
+ */
+ protected static final VetoableChangeListener getChildVetoableChangeListener(
+ Object child)
+ {
+ if (child instanceof VetoableChangeListener)
+ return (VetoableChangeListener) child;
+ else
+ return null;
+ }
+
+ /**
+ * Returns <code>child</code> as an instance of {@link Visibility}, or
+ * <code>null</code> if <code>child</code> does not implement that interface.
+ *
+ * @param child the child (<code>null</code> permitted).
+ *
+ * @return The child cast to {@link Visibility}.
+ */
+ protected static final Visibility getChildVisibility(Object child)
+ {
+ if (child instanceof Visibility)
+ return (Visibility) child;
+ else
+ return null;
+ }
+
+ public Locale getLocale ()
+ {
+ return locale;
+ }
+
+ public URL getResource (String name, BeanContextChild bcc)
+ {
+ if (! contains(bcc))
+ throw new IllegalArgumentException("argument not a child");
+ ClassLoader loader = bcc.getClass().getClassLoader();
+ return (loader == null ? ClassLoader.getSystemResource(name)
+ : loader.getResource(name));
+ }
+
+ public InputStream getResourceAsStream (String name, BeanContextChild bcc)
+ {
+ if (! contains(bcc))
+ throw new IllegalArgumentException("argument not a child");
+ ClassLoader loader = bcc.getClass().getClassLoader();
+ return (loader == null ? ClassLoader.getSystemResourceAsStream(name)
+ : loader.getResourceAsStream(name));
+ }
+
+ protected void initialize ()
+ {
+ bcmListeners = new ArrayList();
+ children = new HashMap();
+ }
+
+ /**
+ * This is a convenience method for instantiating a bean inside this
+ * context. It delegates to the appropriate method in
+ * <code>java.beans.Beans</code> using the context's classloader.
+ *
+ * @param beanName the name of the class of bean to instantiate.
+ * @throws IOException if an I/O error occurs in loading the class.
+ * @throws ClassNotFoundException if the class, <code>beanName</code>,
+ * can not be found.
+ */
+ public Object instantiateChild (String beanName)
+ throws IOException, ClassNotFoundException
+ {
+ return Beans.instantiate(getClass().getClassLoader(), beanName, this);
+ }
+
+ /**
+ * Returns <code>true</code> if the <code>BeanContext</code> is in
+ * design time mode, and <code>false</code> if it is in runtime mode.
+ *
+ * @return A boolean.
+ *
+ * @see #setDesignTime(boolean)
+ */
+ public boolean isDesignTime()
+ {
+ return designTime;
+ }
+
+ /**
+ * Returns true if this bean context has no children.
+ *
+ * @return true if there are no children.
+ */
+ public boolean isEmpty ()
+ {
+ synchronized (children)
+ {
+ return children.isEmpty();
+ }
+ }
+
+ /**
+ * Returns true if the bean context is in the process
+ * of being serialized.
+ *
+ * @return true if the context is being serialized.
+ */
+ public boolean isSerializing()
+ {
+ return serializing;
+ }
+
+ public Iterator iterator ()
+ {
+ synchronized (children)
+ {
+ return children.keySet().iterator();
+ }
+ }
+
+ /**
+ * Returns false as this bean does not a
+ * GUI for its operation.
+ *
+ * @return false
+ */
+ public boolean needsGui()
+ {
+ return false;
+ }
+
+ /**
+ * Informs this bean that it is okay to make use of
+ * the GUI.
+ */
+ public void okToUseGui ()
+ {
+ okToUseGui = true;
+ }
+
+ /**
+ * Subclasses may use this method to catch property changes
+ * arising from the children of this context. At present,
+ * we just listen for the beans being assigned to a different
+ * context and remove them from here if such an event occurs.
+ *
+ * @param pce the property change event.
+ */
+ public void propertyChange (PropertyChangeEvent pce)
+ {
+ if (pce.getNewValue() != this)
+ remove(pce.getSource(), false);
+ }
+
+ /**
+ * Deserializes the children using the
+ * {@link #deserialize(ObjectInputStream, Collection} method
+ * and then calls {@link childDeserializedHook(Object, BCSChild)}
+ * for each child deserialized.
+ *
+ * @param ois the input stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public final void readChildren (ObjectInputStream ois)
+ throws IOException, ClassNotFoundException
+ {
+ List temp = new ArrayList();
+ deserialize(ois, temp);
+ Iterator i = temp.iterator();
+ synchronized (globalHierarchyLock)
+ {
+ synchronized (children)
+ {
+ while (i.hasNext())
+ {
+ BCSChild bcs = (BCSChild) i.next();
+ childDeserializedHook(bcs.getTargetChild(), bcs);
+ children.put(bcs.getTargetChild(), bcs);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove the specified child from the context. This is
+ * the same as calling <code>remove(Object,boolean)</code>
+ * with a request for the <code>setBeanContext()</code> method
+ * of the child to be called (i.e. the second argument is true).
+ *
+ * @param targetChild the child to remove.
+ */
+ public boolean remove (Object targetChild)
+ {
+ return remove(targetChild, true);
+ }
+
+ /**
+ * <p>
+ * Removes a child from the bean context. A child can be a simple
+ * <code>Object</code>, a <code>BeanContextChild</code>
+ * or another <code>BeanContext</code>. If the given child is not
+ * a child of this context, this method returns <code>false</code>.
+ * </p>
+ * <p>
+ * If the child is a <code>BeanContextChild</code>, or a proxy
+ * for such a child, the <code>setBeanContext()</code> method
+ * is invoked on the child (if specified). If this operation is vetoed
+ * by the child, via throwing a <code>PropertyVetoException</code>,
+ * then the current completion state of the <code>remove()</code>
+ * operation is rolled back and a <code>IllegalStateException</code>
+ * is thrown. If the <code>BeanContextChild</code> is successfully
+ * removed, then the context deregisters with its
+ * <code>PropertyChangeListener</code> and
+ * <code>VetoableChangeListener</code> for "beanContext" events.
+ * </p>
+ * <p>
+ * A <code>BeanContextMembershipEvent</code> is fired when the
+ * child is successfully removed from the bean context.
+ * </p>
+ * <p>
+ * This method is synchronized over the global hierarchy lock.
+ * </p>
+ *
+ * @param targetChild the child to remove.
+ * @param callChildSetBC true if the <code>setBeanContext()</code>
+ * method of the child should be called.
+ * @return false if the child doesn't exist.
+ * @throws IllegalArgumentException if the child is null.
+ * @throws IllegalStateException if the child vetos the setting
+ * of its context.
+ */
+ protected boolean remove (Object targetChild, boolean callChildSetBC)
+ {
+ synchronized (globalHierarchyLock)
+ {
+ if (targetChild == null)
+ throw new IllegalArgumentException();
+
+ BCSChild child;
+ synchronized (children)
+ {
+ if (!children.containsKey(targetChild)
+ || !validatePendingRemove(targetChild))
+ return false;
+ child = (BCSChild) children.remove(targetChild);
+ }
+ synchronized (targetChild)
+ {
+ BeanContextChild bcChild = null;
+ if (targetChild instanceof BeanContextChild)
+ bcChild = (BeanContextChild) targetChild;
+ if (targetChild instanceof BeanContextProxy)
+ bcChild = ((BeanContextProxy) targetChild).getBeanContextProxy();
+ if (bcChild != null)
+ try
+ {
+ if (callChildSetBC)
+ bcChild.setBeanContext(null);
+ bcChild.removeVetoableChangeListener("beanContext", this);
+ bcChild.removePropertyChangeListener("beanContext", this);
+ }
+ catch (PropertyVetoException e)
+ {
+ synchronized (children)
+ {
+ children.put(targetChild, child);
+ }
+ throw new IllegalStateException("The child refused to " +
+ "disassociate itself with " +
+ "this context.", e);
+ }
+ childJustRemovedHook(targetChild, child);
+ }
+ fireChildrenRemoved(new BeanContextMembershipEvent(this,
+ new Object[]{ targetChild }));
+ return true;
+ }
+ }
+
+ public boolean removeAll (Collection c)
+ {
+ // Intentionally throws an exception.
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeBeanContextMembershipListener (BeanContextMembershipListener bcml)
+ {
+ synchronized (bcmListeners)
+ {
+ bcmListeners.remove(bcml);
+ }
+ }
+
+ public boolean retainAll (Collection c)
+ {
+ // Intentionally throws an exception.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Writes the items in the collection to the specified output stream. Items
+ * in the collection that are not instances of {@link Serializable}
+ * (this includes <code>null</code>) are simply ignored.
+ *
+ * @param oos the output stream (<code>null</code> not permitted).
+ * @param coll the collection (<code>null</code> not permitted).
+ *
+ * @throws IOException
+ *
+ * @see #deserialize(ObjectInputStream, Collection)
+ */
+ protected final void serialize(ObjectOutputStream oos, Collection coll)
+ throws IOException
+ {
+ Object[] items = coll.toArray();
+ int itemCount = 0;
+ for (int i = 0; i < items.length; i++)
+ {
+ if (items[i] instanceof Serializable)
+ itemCount++;
+ }
+ oos.writeInt(itemCount);
+ for (int i = 0; i < items.length; i++)
+ {
+ if (items[i] instanceof Serializable)
+ oos.writeObject(items[i]);
+ }
+ }
+
+ /**
+ * Sets the flag that indicates whether or not the
+ * <code>BeanContext</code> is in design mode. If the flag changes
+ * value, a {@link PropertyChangeEvent} (with the property name 'designMode')
+ * is sent to registered listeners. Note that the property name used here
+ * does NOT match the specification in the {@link DesignMode} interface, we
+ * match the reference implementation instead - see bug parade entry 4295174.
+ *
+ * @param dtime the new value for the flag.
+ *
+ * @see #isDesignTime()
+ */
+ public void setDesignTime(boolean dtime)
+ {
+ boolean save = designTime;
+ designTime = dtime;
+ // note that we use the same property name as Sun's implementation,
+ // even though this is a known bug: see bug parade entry 4295174
+ firePropertyChange("designMode", Boolean.valueOf(save),
+ Boolean.valueOf(dtime));
+ }
+
+ public void setLocale (Locale newLocale)
+ throws PropertyVetoException
+ {
+ if (newLocale == null || locale == newLocale)
+ return;
+ fireVetoableChange("locale", locale, newLocale);
+ Locale oldLocale = locale;
+ locale = newLocale;
+ firePropertyChange("locale", oldLocale, newLocale);
+ }
+
+ public int size ()
+ {
+ synchronized (children)
+ {
+ return children.size();
+ }
+ }
+
+ /**
+ * Returns an array containing the children of this <code>BeanContext</code>.
+ *
+ * @return An array containing the children.
+ */
+ public Object[] toArray()
+ {
+ synchronized (children)
+ {
+ return children.keySet().toArray();
+ }
+ }
+
+ /**
+ * Populates, then returns, the supplied array with the children of this
+ * <code>BeanContext</code>. If the array is too short to hold the
+ * children, a new array is allocated and returned. If the array is too
+ * long, it is padded with <code>null</code> items at the end.
+ *
+ * @param array an array to populate (<code>null</code> not permitted).
+ */
+ public Object[] toArray(Object[] array)
+ {
+ synchronized (children)
+ {
+ return children.keySet().toArray(array);
+ }
+ }
+
+ protected boolean validatePendingAdd (Object targetChild)
+ {
+ return true;
+ }
+
+ protected boolean validatePendingRemove (Object targetChild)
+ {
+ return true;
+ }
+
+ /**
+ * Subclasses may use this method to veto changes arising
+ * from the children of this context.
+ *
+ * @param pce the vetoable property change event fired.
+ */
+ public void vetoableChange (PropertyChangeEvent pce)
+ throws PropertyVetoException
+ {
+ /* Purposefully left empty */
+ }
+
+ /**
+ * Serializes the children using the
+ * {@link #serialize(ObjectOutputStream, Collection} method.
+ *
+ * @param oos the output stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public final void writeChildren (ObjectOutputStream oos)
+ throws IOException
+ {
+ synchronized (children)
+ {
+ serialize(oos, children.values());
+ }
+ }
+
+}
diff --git a/libjava/classpath/java/beans/beancontext/package.html b/libjava/classpath/java/beans/beancontext/package.html
new file mode 100644
index 000000000..55e3bd723
--- /dev/null
+++ b/libjava/classpath/java/beans/beancontext/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in java.beans.beancontext package.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - java.beans.beancontext</title></head>
+
+<body>
+<p>Containers and execution environments for beans.</p>
+
+</body>
+</html>
diff --git a/libjava/classpath/java/beans/package.html b/libjava/classpath/java/beans/package.html
new file mode 100644
index 000000000..5ca800037
--- /dev/null
+++ b/libjava/classpath/java/beans/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in java.beans package.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - java.beans</title></head>
+
+<body>
+<p>Listeners and descriptors for managing beans.</p>
+
+</body>
+</html>