From c8875fb97fc03779a5bba09872227b1d08e5d52a Mon Sep 17 00:00:00 2001 From: tromey Date: Sat, 16 Jul 2005 00:30:23 +0000 Subject: Initial revision git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102074 138bc75d-0d04-0410-961f-82ee72b054a4 --- .../classpath/java/beans/AppletInitializer.java | 61 +++ libjava/classpath/java/beans/BeanDescriptor.java | 89 +++ libjava/classpath/java/beans/BeanInfo.java | 181 ++++++ libjava/classpath/java/beans/Beans.java | 368 +++++++++++++ libjava/classpath/java/beans/Customizer.java | 86 +++ libjava/classpath/java/beans/DesignMode.java | 93 ++++ libjava/classpath/java/beans/EventHandler.java | 606 ++++++++++++++++++++ .../classpath/java/beans/EventSetDescriptor.java | 442 +++++++++++++++ .../classpath/java/beans/ExceptionListener.java | 57 ++ libjava/classpath/java/beans/Expression.java | 133 +++++ .../classpath/java/beans/FeatureDescriptor.java | 232 ++++++++ .../java/beans/IndexedPropertyDescriptor.java | 307 +++++++++++ .../java/beans/IntrospectionException.java | 67 +++ libjava/classpath/java/beans/Introspector.java | 608 +++++++++++++++++++++ libjava/classpath/java/beans/MethodDescriptor.java | 88 +++ .../classpath/java/beans/ParameterDescriptor.java | 52 ++ .../classpath/java/beans/PropertyChangeEvent.java | 189 +++++++ .../java/beans/PropertyChangeListener.java | 61 +++ .../java/beans/PropertyChangeListenerProxy.java | 102 ++++ .../java/beans/PropertyChangeSupport.java | 488 +++++++++++++++++ .../classpath/java/beans/PropertyDescriptor.java | 583 ++++++++++++++++++++ libjava/classpath/java/beans/PropertyEditor.java | 209 +++++++ .../java/beans/PropertyEditorManager.java | 215 ++++++++ .../java/beans/PropertyEditorSupport.java | 265 +++++++++ .../java/beans/PropertyVetoException.java | 85 +++ libjava/classpath/java/beans/SimpleBeanInfo.java | 139 +++++ libjava/classpath/java/beans/Statement.java | 326 +++++++++++ libjava/classpath/java/beans/TODO | 4 + .../java/beans/VetoableChangeListener.java | 73 +++ .../java/beans/VetoableChangeListenerProxy.java | 102 ++++ .../java/beans/VetoableChangeSupport.java | 530 ++++++++++++++++++ libjava/classpath/java/beans/Visibility.java | 85 +++ libjava/classpath/java/beans/XMLDecoder.java | 307 +++++++++++ .../java/beans/beancontext/BeanContext.java | 272 +++++++++ .../java/beans/beancontext/BeanContextChild.java | 174 ++++++ .../BeanContextChildComponentProxy.java | 60 ++ .../beans/beancontext/BeanContextChildSupport.java | 381 +++++++++++++ .../beancontext/BeanContextContainerProxy.java | 63 +++ .../java/beans/beancontext/BeanContextEvent.java | 110 ++++ .../beancontext/BeanContextMembershipEvent.java | 112 ++++ .../beancontext/BeanContextMembershipListener.java | 70 +++ .../java/beans/beancontext/BeanContextProxy.java | 65 +++ .../BeanContextServiceAvailableEvent.java | 95 ++++ .../beancontext/BeanContextServiceProvider.java | 138 +++++ .../BeanContextServiceProviderBeanInfo.java | 60 ++ .../BeanContextServiceRevokedEvent.java | 110 ++++ .../BeanContextServiceRevokedListener.java | 62 +++ .../beans/beancontext/BeanContextServices.java | 216 ++++++++ .../beancontext/BeanContextServicesListener.java | 56 ++ .../beancontext/BeanContextServicesSupport.java | 300 ++++++++++ .../java/beans/beancontext/BeanContextSupport.java | 460 ++++++++++++++++ .../classpath/java/beans/beancontext/package.html | 46 ++ libjava/classpath/java/beans/package.html | 46 ++ 53 files changed, 10129 insertions(+) create mode 100644 libjava/classpath/java/beans/AppletInitializer.java create mode 100644 libjava/classpath/java/beans/BeanDescriptor.java create mode 100644 libjava/classpath/java/beans/BeanInfo.java create mode 100644 libjava/classpath/java/beans/Beans.java create mode 100644 libjava/classpath/java/beans/Customizer.java create mode 100644 libjava/classpath/java/beans/DesignMode.java create mode 100644 libjava/classpath/java/beans/EventHandler.java create mode 100644 libjava/classpath/java/beans/EventSetDescriptor.java create mode 100644 libjava/classpath/java/beans/ExceptionListener.java create mode 100644 libjava/classpath/java/beans/Expression.java create mode 100644 libjava/classpath/java/beans/FeatureDescriptor.java create mode 100644 libjava/classpath/java/beans/IndexedPropertyDescriptor.java create mode 100644 libjava/classpath/java/beans/IntrospectionException.java create mode 100644 libjava/classpath/java/beans/Introspector.java create mode 100644 libjava/classpath/java/beans/MethodDescriptor.java create mode 100644 libjava/classpath/java/beans/ParameterDescriptor.java create mode 100644 libjava/classpath/java/beans/PropertyChangeEvent.java create mode 100644 libjava/classpath/java/beans/PropertyChangeListener.java create mode 100644 libjava/classpath/java/beans/PropertyChangeListenerProxy.java create mode 100644 libjava/classpath/java/beans/PropertyChangeSupport.java create mode 100644 libjava/classpath/java/beans/PropertyDescriptor.java create mode 100644 libjava/classpath/java/beans/PropertyEditor.java create mode 100644 libjava/classpath/java/beans/PropertyEditorManager.java create mode 100644 libjava/classpath/java/beans/PropertyEditorSupport.java create mode 100644 libjava/classpath/java/beans/PropertyVetoException.java create mode 100644 libjava/classpath/java/beans/SimpleBeanInfo.java create mode 100644 libjava/classpath/java/beans/Statement.java create mode 100644 libjava/classpath/java/beans/TODO create mode 100644 libjava/classpath/java/beans/VetoableChangeListener.java create mode 100644 libjava/classpath/java/beans/VetoableChangeListenerProxy.java create mode 100644 libjava/classpath/java/beans/VetoableChangeSupport.java create mode 100644 libjava/classpath/java/beans/Visibility.java create mode 100644 libjava/classpath/java/beans/XMLDecoder.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContext.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextChild.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextProxy.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServices.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextSupport.java create mode 100644 libjava/classpath/java/beans/beancontext/package.html create mode 100644 libjava/classpath/java/beans/package.html (limited to 'libjava/classpath/java/beans') diff --git a/libjava/classpath/java/beans/AppletInitializer.java b/libjava/classpath/java/beans/AppletInitializer.java new file mode 100644 index 00000000000..69dc2cae50e --- /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 + * Beans.instantiate(). + * + * @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 Beans.instantiate() + * 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 00000000000..21227b2fee0 --- /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.

+ ** + ** @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 00000000000..525500a389c --- /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.

+ ** + ** When you have written the class, give it the name + ** <Bean Class Name>BeanInfo and place it in + ** the same package as the Bean, or in the bean info search path + ** (see Introspector for information on search paths).

+ ** + ** 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).

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 null 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 + ** -1 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 null 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 + ** -1 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 + ** null 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).

+ ** + ** 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: + **

    + **
  1. This BeanInfo object.
  2. + **
  3. getAdditionalBeanInfo()[getAdditionalBeanInfo().length]
  4. + **
  5. ...
  6. + **
  7. getAdditionalBeanInfo()[1]
  8. + **
  9. getAdditionalBeanInfo()[0]
  10. + **

+ ** + ** Spec Note: It is possible that + ** returning null 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. + ** null 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.

+ ** + ** Spec Note: 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 00000000000..ffcb83fc1f3 --- /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; + +/** + * Beans 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. + *

This is a convenience method that calls instantiate(cl, beanName, null, null).

+ * + * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer) + * @param cl ClassLoader to be used or null 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. + * + *

This is a convenience method that calls instantiate(cl, beanName, beanContext, null).

+ * + * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer) + * @param cl ClassLoader to be used or null 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. + * + *

In Beans 1.0 the instantiation scheme is as follows:

+ *

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 + * ClassLoader was provided.

+ * + *

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.

+ * + *

If a BeanContext instance is available the created bean is added to it.

+ * + *

If the created Bean is an Applet or subclass and an AppletInitializer + * instance is available the applet is initialized and afterwards activated using the initializer. Additionally + * every instantiated Applet bean is initialized using the {@link Applet.init} method. + * Furthermore every applet gets a default AppletStub. The Applet'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.

+ * + *

A ClassNotFoundException is not only thrown when a class name was unknown + * but even when the class has public no-argument constructor + * (IllegalAccessException is wrapped) or an exception is thrown while + * invoking such a constructor (causing exception is wrapped).

+ * + * @param cl ClassLoader to be used or null 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 Applet 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 newClass 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. + *

Defaults to true.

+ * + * @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. + *

Defaults to false.

+ * + * @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/Customizer.java b/libjava/classpath/java/beans/Customizer.java new file mode 100644 index 00000000000..b36c89f8846 --- /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.

+ ** + ** A Customizer is meant to be embedded in an RAD tool, + ** and thus must be a descendant of java.awt.Component.

+ ** + ** 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.

+ ** + ** 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.

+ ** + ** 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 after 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/DesignMode.java b/libjava/classpath/java/beans/DesignMode.java new file mode 100644 index 00000000000..39805d50c18 --- /dev/null +++ b/libjava/classpath/java/beans/DesignMode.java @@ -0,0 +1,93 @@ +/* java.beans.DesignMode + 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; + +/** + * BeanContextChild implementors implement this to get information about whether they are in a design time or runtime environment. + * The reason this is restricted to BeanContextChildren is that + * only things in the BeanContext 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 PropertyChangeEvents from your Bean. + * @fixme Check whether PROPERTYNAME is set to same value as Sun. + */ + String PROPERTYNAME = "designTime"; + + /** + * The environment will call this method on your + * BeanContextChild when it is registered in a parent + * BeanContext or when behavior needs to switch from + * design time to runtime behavior (or vice versa). + *

+ * + * BeanContexts are required to fire + * PropertyChangeEvents when properties change. + * designTime is a property, and therefore when you + * implement setDesignTime(), you need to fire a + * PropertyChangeEvent with the old value, the new + * value and using PROPERTYNAME as the property name. + * + * @param designTime the new value of design time, + * true if it is design time, + * false if it is runtime. + * + * @fixme I'm frankly not really sure whether it's the case that + * the BeanContext can change the status of the Bean from + * design time to runtime. But it appears that it may be so. + * + * @see java.util.PropertyChangeEvent + * @see java.beans.beancontext.BeanContext + * @see #PROPERTYNAME + */ + void setDesignTime(boolean designTime); + + /** + * This method should tell whether it is design time or runtime. + * @return true if design time, false if + * runtime. + */ + boolean isDesignTime(); +} diff --git a/libjava/classpath/java/beans/EventHandler.java b/libjava/classpath/java/beans/EventHandler.java new file mode 100644 index 00000000000..9c85893e0f3 --- /dev/null +++ b/libjava/classpath/java/beans/EventHandler.java @@ -0,0 +1,606 @@ +/* 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; + +/** + *

EventHandler forms a bridge between dynamically created listeners and + * arbitrary properties and methods.

+ * + *

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 create you can create + * these listener implementations.

+ * + *

See the documentation of each method for usage examples.

+ * + * @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 EventHandler instance. + * + *

Typical creation is done with the create method, not by knewing an + * EventHandler.

+ * + *

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.

+ * + *

Throws a NullPointerException if the target + * argument is null. + * + * @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), + null); + } + catch (NoSuchMethodException nsme1) + { + try { + // Look for regular property getter getProperty + getter = o.getClass().getMethod("get" + capitalize(prop), + null); + } catch(NoSuchMethodException nsme2) { + try { + // Finally look for a method of the name prop + getter = o.getClass().getMethod(prop, null); + } 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, null); + + 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 EventHandler. + * + *

This method is normally called by the listener's proxy implementation.

+ * + * @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 NoSuchMethodException 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, null); + } + 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, null); + } 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); + } + } + + /** + *

Returns the primitive type for every wrapper class or the + * class itself if it is no wrapper class.

+ * + *

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.

+ */ + 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(); + } + } + + /** + *

Constructs an implementation of listenerInterface + * to dispatch events.

+ * + *

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.

+ * + *

Call this method like:

+ * + * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, target, "dispose")); + * + * + *

to achieve the following behavior:

+ * + * button.addActionListener(new ActionListener() { + * public void actionPerformed(ActionEvent ae) { + * target.dispose(); + * } + * }); + * + * + *

That means if you need a listener implementation that simply calls a + * a no-argument method on a given instance for each + * method of the listener interface.

+ * + *

Note: The action 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 ArrayIndexOutOfBoundsException + * whenever one of the listener methods is called.

+ * + *

The EventHandler 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.

+ * + *

In case that the method of the target object throws an exception + * it will be wrapped in a RuntimeException and thrown out + * of the listener method.

+ * + *

In case that the method of the target object cannot be found an + * ArrayIndexOutOfBoundsException will be thrown when the + * listener method is invoked.

+ * + *

A call to this method is equivalent to: + * create(listenerInterface, target, action, null, null)

+ * + * @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 Object create(Class listenerInterface, Object target, String action) + { + return create(listenerInterface, target, action, null, null); + } + + /** + *

Constructs an implementation of listenerInterface + * to dispatch events.

+ * + *

Use this method if you want to create an implementation that retrieves + * a property value from the first 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.

+ * + *

You can set the value of eventPropertyName to "prop" + * to denote the retrieval of a property named "prop" from the event + * object. In case that no such property exists the EventHandler + * will try to find a method with that name.

+ * + *

If you set eventPropertyName to a value like this "a.b.c" + * EventHandler will recursively evaluate the properties "a", "b" + * and "c". Again if no property can be found the EventHandler + * 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.

+ * + *

An exception thrown in any of these methods will provoke a + * RuntimeException to be thrown which contains an + * InvocationTargetException containing the triggering exception.

+ * + *

If you set eventPropertyName to a non-null value the + * action parameter will be interpreted as a property name + * or a method name of the target object.

+ * + *

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.

+ * + *

Examples:

+ *

The following code:

+ * button.addActionListener( + * new ActionListener() { + * public void actionPerformed(ActionEvent ae) { + * Object o = ae.getSource().getClass().getName(); + * textField.setText((String) o); + * } + * }); + * + * + *

Can be expressed using the EventHandler like this:

+ *

+ * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "text", "source.class.name"); + * + *

+ * + *

As said above you can specify the target as a method, too:

+ *

+ * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "setText", "source.class.name"); + * + *

+ * + *

Furthermore you can use method names in the property:

+ *

+ * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "setText", "getSource.getClass.getName"); + * + *

+ * + *

Finally you can mix names:

+ *

+ * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "setText", "source.getClass.name"); + * + *

+ * + *

A call to this method is equivalent to: + * create(listenerInterface, target, action, null, null) + *

+ * + * @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 Object create(Class listenerInterface, Object target, + String action, String eventPropertyName) + { + return create(listenerInterface, target, action, eventPropertyName, null); + } + + /** + *

Constructs an implementation of listenerInterface + * to dispatch events.

+ * + *

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 EventHandler's + * usage.

+ * + *

If you want to call dispose on a JFrame instance + * when the WindowListener.windowClosing() method was invoked use + * the following code:

+ *

+ * + * EventHandler.create(WindowListener.class, jframeInstance, "dispose", null, "windowClosing"); + * + *

+ * + *

A NullPointerException is thrown if the listenerInterface + * or target argument are null. + * + * @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 Object create(Class 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 proxy; + } + +} diff --git a/libjava/classpath/java/beans/EventSetDescriptor.java b/libjava/classpath/java/beans/EventSetDescriptor.java new file mode 100644 index 00000000000..8624e643476 --- /dev/null +++ b/libjava/classpath/java/beans/EventSetDescriptor.java @@ -0,0 +1,442 @@ +/* java.beans.EventSetDescriptor + 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.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. + ** + ** 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.

+ ** + ** The methods have these constraints on them:

+ **

    + **
  • event firing methods: must have void 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.)
  • + **
  • add listener method: must have void return value. Must + ** take exactly one argument, of the listener class's type. May fire either + ** zero exceptions, or one exception of type java.util.TooManyListenersException. + ** Must be public.
  • + **
  • remove listener method: must have void return value. + ** Must take exactly one argument, of the listener class's type. May not + ** fire any exceptions. Must be public.
  • + **
+ ** + ** A final constraint is that event listener classes must extend from EventListener.

+ ** + ** There are also various design patterns associated with some of the methods + ** of construction. Those are explained in more detail in the appropriate + ** constructors.

+ ** + ** Documentation Convention: 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 programmatic or localized to + ** make this distinction clear. + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 31 May 1998 + **/ + +public class EventSetDescriptor extends FeatureDescriptor { + private Method addListenerMethod; + private Method removeListenerMethod; + private Class listenerType; + private MethodDescriptor[] listenerMethodDescriptors; + private Method[] listenerMethods; + + private boolean unicast; + private boolean inDefaultEventSet = true; + + /** Create a new EventSetDescriptor. + ** This version of the constructor enforces the rules imposed on the methods + ** described at the top of this class, as well as searching for:

+ **

    + **
  1. The event-firing method must be non-private with signature + ** void <listenerMethodName>(<eventSetName>Event) + ** (where <eventSetName> has its first character capitalized + ** by the constructor and the Event is a descendant of + ** java.util.EventObject) in class listenerType + ** (any exceptions may be thrown). + ** Implementation note: Note that there could conceivably be multiple + ** methods with this type of signature (example: java.util.MouseEvent vs. + ** my.very.own.MouseEvent). In this implementation, all methods fitting the + ** description will be put into the EventSetDescriptor, 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.
  2. + **
  3. The add and remove methods must be public and named + ** void add<eventSetName>Listener(<listenerType>) and + ** void remove<eventSetName>Listener(<listenerType>) in + ** in class eventSourceClass, where + ** <eventSetName> will have its first letter capitalized. + ** Standard exception rules (see class description) apply.
  4. + **
+ ** @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."); + } + } + + /** Create a new EventSetDescriptor. + ** 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.

+ ** + ** @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."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of constructor allows you to explicitly say which methods do what, and + ** no reflection is done by the EventSetDescriptor. 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."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of constructor allows you to explicitly say which methods do what, and + ** no reflection is done by the EventSetDescriptor. 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 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Get the class that contains the event firing methods. **/ + public Class getListenerType() { + return listenerType; + } + + /** Get the event firing methods. **/ + public Method[] getListenerMethods() { + return listenerMethods; + } + + /** Get the event firing methods as MethodDescriptors. **/ + public MethodDescriptor[] getListenerMethodDescriptors() { + if(listenerMethodDescriptors == null) { + listenerMethodDescriptors = new MethodDescriptor[listenerMethods.length]; + for(int i=0;i 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 + * + * Documentation Convention: 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 programmatic or localized 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 valueHash; + + /** + * Instantiate this FeatureDescriptor with appropriate default values. + */ + public FeatureDescriptor() + { + valueHash = new Hashtable(); + } + + /** + * 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 getDisplayName 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 attributeNames() + { + return valueHash.keys(); + } +} diff --git a/libjava/classpath/java/beans/IndexedPropertyDescriptor.java b/libjava/classpath/java/beans/IndexedPropertyDescriptor.java new file mode 100644 index 00000000000..efdc7b40238 --- /dev/null +++ b/libjava/classpath/java/beans/IndexedPropertyDescriptor.java @@ -0,0 +1,307 @@ +/* java.beans.IndexedPropertyDescriptor + 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.

+ ** + ** An example property would have four methods like this:

+ ** FooBar[] getFoo()
+ ** void setFoo(FooBar[])
+ ** FooBar getFoo(int)
+ ** void setFoo(int,FooBar)

+ ** + ** The constraints put on get and set methods are:

+ **

    + **
  1. There must be at least a get(int) or a set(int,...) method. + ** Nothing else is required. Spec note: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.)
  2. + **
  3. A get array method must have signature + ** <propertyType>[] <getMethodName>()
  4. + **
  5. A set array method must have signature + ** void <setMethodName>(<propertyType>[])
  6. + **
  7. A get index method must have signature + ** <propertyType> <getMethodName>(int)
  8. + **
  9. A set index method must have signature + ** void <setMethodName>(int,<propertyType>)
  10. + **
  11. All these methods may throw any exception.
  12. + **
  13. All these methods must be public.
  14. + **
+ ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 26 Jul 1998 + **/ + +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 get<name>() + ** and setter methods named + ** set<name>() in class + ** <beanClass>, where <name> has its + ** first letter capitalized by the constructor.

+ ** + ** Implementation note: 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.

+ ** + ** Spec note: + ** 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.

+ ** + ** Implementation note: 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.

+ ** + ** Spec note: + ** 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; + } + + public Method getIndexedWriteMethod() { + return setIndex; + } + + 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 + * + * 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).

+ * + * Order of Operations

+ * + * 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 <bean class name>BeanInfo in different + * packages, first searching the bean class's package + * and then moving on to search the beanInfoSearchPath.

+ * + * 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).

+ * + * 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.

+ * + * Introspection Design Patterns

+ * + * 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). + * + * + * Properties:

+ * + *

    + *
  1. If there is a public boolean isXXX() + * method, then XXX is a read-only boolean property. + * boolean getXXX() 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 + * public void setXXX(boolean) method, + * it is part of this group and makes it a read-write + * property.
  2. + *
  3. If there is a + * public <type> getXXX(int) + * method, then XXX is a read-only indexed property of + * type <type>. If there is a + * public void setXXX(int,<type>) + * method, then it is a read-write indexed property of + * type <type>. There may also be a + * public <type>[] getXXX() and a + * public void setXXX(<type>) + * method as well.
  4. + *
  5. If there is a + * public void setXXX(int,<type>) + * method, then it is a write-only indexed property of + * type <type>. There may also be a + * public <type>[] getXXX() and a + * public void setXXX(<type>) + * method as well.
  6. + *
  7. If there is a + * public <type> getXXX() method, + * then XXX is a read-only property of type + * <type>. If there is a + * public void setXXX(<type>) + * method, then it will be used for the property and + * the property will be considered read-write.
  8. + *
  9. If there is a + * public void setXXX(<type>) + * 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 <type>.
  10. + *
  11. In all of the above cases, if the setXXX() method + * throws PropertyVetoException, then the + * property in question is assumed to be constrained. + * No properties are ever assumed to be bound + * (Spec Note: this is not in the + * spec, it just makes sense). See PropertyDescriptor + * for a description of bound and constrained + * properties.
  12. + *
+ * + * Events:

+ * + * If there is a pair of methods, + * public void addXXX(<type>) and + * public void removeXXX(<type>), where + * <type> is a descendant of + * java.util.EventListener, then the pair of + * methods imply that this Bean will fire events to + * listeners of type <type>.

+ * + * If the addXXX() method throws + * java.util.TooManyListenersException, then + * the event set is assumed to be unicast. See + * EventSetDescriptor for a discussion of unicast event + * sets.

+ * + * Spec Note: 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.

+ * + * Methods:

+ * + * 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 beanInfoCache = new Hashtable(); + + private Introspector() {} + + /** + * Get the BeanInfo for class beanClass, + * 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 = (BeanInfo)beanInfoCache.get(beanClass); + if(cachedInfo != null) + { + return cachedInfo; + } + cachedInfo = getBeanInfo(beanClass,null); + beanInfoCache.put(beanClass,cachedInfo); + return cachedInfo; + } + } + + /** + * 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); + } + } + + /** + * Get the BeanInfo for class beanClass, + * 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 topClass. + * + * @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(); + PropertyDescriptor[] p = explicit.explicitPropertyDescriptors; + if(p!=null) + { + for(int i=0;iIf 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 00000000000..a97e6e1c2e9 --- /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 after 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 00000000000..68a8153032b --- /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 PropertyChangeListener - + * 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 00000000000..a0e64af4d29 --- /dev/null +++ b/libjava/classpath/java/beans/PropertyChangeSupport.java @@ -0,0 +1,488 @@ +/* PropertyChangeSupport.java -- support to manage property change listeners + Copyright (C) 1998, 1999, 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.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 children 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, n adds with the same listener will + * result in n events being sent to that listener for every + * property change. Adding a null listener may cause a NullPointerException + * down the road. 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 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 add() has been called multiple times for a + * particular listener, remove() 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 + * PropertyChangeListenerProxy, 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, n adds on a particular + * property for a particular listener will result in n 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 may cause a NullPointerException down the road. 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) + { + 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 add() has been called multiple times for a particular + * listener on a property, remove() 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, this returns + * an empty array. + * + * @return the array of registered listeners + * @throws NullPointerException if propertyName is null + * @since 1.4 + */ + public synchronized PropertyChangeListener[] + getPropertyChangeListeners(String propertyName) + { + if (children == 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, + new Integer(oldVal), + new Integer(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); + } + } + } + + /** + * Tell whether the specified property is being listened on or not. This + * will only return true 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 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 00000000000..416d468576f --- /dev/null +++ b/libjava/classpath/java/beans/PropertyDescriptor.java @@ -0,0 +1,583 @@ +/* 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.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.)

+ ** + ** The constraints put on get and set methods are:

+ **

    + **
  1. A get method must have signature + ** <propertyType> <getMethodName>()
  2. + **
  3. A set method must have signature + ** void <setMethodName>(<propertyType>)
  4. + **
  5. Either method type may throw any exception.
  6. + **
  7. Both methods must be public.
  8. + **
+ ** + ** @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 get<name>() + ** (or, optionally, if the property is boolean, + ** is<name>()) and + ** set<name>() in class + ** <beanClass>, where <name> has its + ** first letter capitalized by the constructor.

+ ** + ** Note that using this constructor the given property must be read- and + ** writeable. If the implementation does not both, a read and a write method, an + ** IntrospectionException is thrown. + ** + ** Implementation note: 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

+ ** + ** @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.

+ ** + ** Implementation note: 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.

+ ** + ** Spec note: + ** 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 null if the property is write-only. + ** @param setMethodName the name of the set method or null 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. + **
+ ** It is possible to call this method with both Method arguments + ** being null. In such a case the property type is null. + ** + ** @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 null if the property is write-only. + ** @param writeMethod the write method or null 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.
+ * 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 + * void. If this methods succeeds the property type + * is adjusted to the return type of the read method.
+ *
+ * It is legal to set the read and the write method to null + * or provide method which have been declared in distinct classes. + * + * @param readMethod The new method to be used or null. + * @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.
+ * 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.
+ *
+ * It is legal to set the read and the write method to null + * or provide method which have been declared in distinct classes. + * + * @param writeMethod The new method to be used or null. + * @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.

+ ** If these things are not true, then the behavior of the system + ** will be undefined.

+ ** + ** When a property is bound, its set method is required to fire the + ** PropertyChangeListener.propertyChange()) 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 java.beans.PropertyVetoException + ** (or subclass thereof) and the bean implements addVetoableChangeListener() + ** and removeVetoableChangeListener(), then setConstrained(true) may safely + ** be called. Otherwise, the system behavior is undefined. + ** Spec note: given those strict parameters, it would be nice if it + ** got set automatically by detection, but oh well.

+ ** When a property is constrained, its set method is required to:

+ **

    + **
  1. Fire the VetoableChangeListener.vetoableChange() + ** event notifying others of the change and allowing them a chance to + ** say it is a bad thing.
  2. + **
  3. 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.
  4. + **
  5. If all has gone well to this point, the value may be changed.
  6. + **
+ ** @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; + } + + 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 Method instances are legal read and + * write methods. The following requirements must be met:
+ *
    + *
  • the read method must not have an argument
  • + *
  • the read method must have a non void return type
  • + *
  • the read method may not exist
  • + *
  • the write method must have a single argument
  • + *
  • the property type and the read method's return type must be assignable from the + * write method's argument type
  • + *
  • the write method may not exist
  • + *
+ * While checking the methods a common new property type is calculated. If the method + * succeeds this property type is returned.
+ *
+ * For compatibility this has to be noted:
+ * 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; + } + + /** Compares this PropertyDescriptor against the + * given object. + * Two PropertyDescriptors are equals if + *
    + *
  • the read methods are equal
  • + *
  • the write methods are equal
  • + *
  • the property types are equals
  • + *
  • the property editor classes are equal
  • + *
  • the flags (constrained and bound) are equal
  • + *
+ * @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 00000000000..d1c5103419f --- /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).

+ ** + ** 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.

+ ** + ** 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.

+ ** + ** PropertyEditors also must support the ability to return a Java + ** initialization string. See the getJavaInitializationString() method for + ** details.

+ ** + ** 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. + **

    + **
  1. 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.
  2. + **
  3. Every PropertyEditor must support getJavaInitializationString().
  4. + **
  5. 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.
  6. + **
  7. 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().
  8. + **
  9. 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().
  10. + **
  11. 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.
  12. + **
+ ** + ** 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.

+ ** + ** 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().

+ ** Return null if you do not support getAsText()/setAsText(). + ** setAsText(getAsText()) 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.

+ ** 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.

+ ** The component must hook up with the PropertyEditor and, whenever a + ** change to the value is made, fire a PropertyChangeEvent to the source.

+ ** @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.

+ ** 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:

+ **

    + **
  1. 2
  2. + **
  3. "I am a String"
  4. + **
  5. new MyObject(2, "String", new StringBuffer())
  6. + **
+ ** @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 00000000000..da2a5678c5c --- /dev/null +++ b/libjava/classpath/java/beans/PropertyEditorManager.java @@ -0,0 +1,215 @@ +/* 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).

+ * + * 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. + * + *

Default property editors are provided for:

+ * + *
    + *
  1. boolean, byte, short, int, long, float, and double
  2. + *
  3. java.lang.String
  4. + *
  5. java.awt.Color
  6. + *
  7. java.awt.Font
  8. + *
+ * + *

Spec Suggestion: Perhaps an editor for + * Filename or something like it should be provided. As well + * as char.

+ * + * @author John Keiser + * @since 1.1 + * @version 1.1.0, 29 Jul 1998 + */ + +public class PropertyEditorManager +{ + static java.util.Hashtable editors = new java.util.Hashtable(); + 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 + * + * 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 protected 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 source is null, + * 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 protected 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 false + */ + 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).

+ * Implementation Note: 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. + * Implementation Note: 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 null + */ + public String[] getTags() + { + return null; + } + + /** Returns a custom component to edit the value. + * + * @return null 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 false 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 PropertyEditor. + * + * @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 00000000000..1f0399b4bfb --- /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 00000000000..cfb96048498 --- /dev/null +++ b/libjava/classpath/java/beans/SimpleBeanInfo.java @@ -0,0 +1,139 @@ +/* java.beans.SimpleBeanInfo + 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.awt.Image; +import java.awt.Toolkit; + +/** + ** 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).

+ ** + ** 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.

+ ** + ** 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 null. + **/ + public BeanDescriptor getBeanDescriptor() { + return null; + } + + /** Force Introspection of the events this Bean type + ** fires. + ** @return null + **/ + public EventSetDescriptor[] getEventSetDescriptors() { + return null; + } + + /** Say that there is no "default" event set. + ** @return -1. + **/ + public int getDefaultEventIndex() { + return -1; + } + + /** Force Introspection of the Bean properties. + ** @return null. + **/ + public PropertyDescriptor[] getPropertyDescriptors() { + return null; + } + + /** Say that there is no "default" property. + ** @return -1. + **/ + public int getDefaultPropertyIndex() { + return -1; + } + + /** Force Introspection of the Bean's methods. + ** @return null. + **/ + public MethodDescriptor[] getMethodDescriptors() { + return null; + } + + /** Tell the Introspector to go look for other BeanInfo + ** itself. + ** @return null. + **/ + public BeanInfo[] getAdditionalBeanInfo() { + return null; + } + + /** Say that this Bean has no icons. + ** @param iconType the type of icon + ** @return null. + **/ + 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. + **/ + public Image loadImage(String location) { + return Toolkit.getDefaultToolkit().getImage(getClass().getResource(location)); + } +} + diff --git a/libjava/classpath/java/beans/Statement.java b/libjava/classpath/java/beans/Statement.java new file mode 100644 index 00000000000..01f86dd286f --- /dev/null +++ b/libjava/classpath/java/beans/Statement.java @@ -0,0 +1,326 @@ +/* java.beans.Statement + Copyright (C) 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; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * class Statement + * + * 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. + * + * @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; + + /** + * Constructs a statement 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 Statement(Object target, String methodName, Object[] arguments) + { + this.target = target; + this.methodName = methodName; + this.arguments = arguments; + } + + /** + * Execute the statement. + * + * Finds the specified method in the target object and calls it with + * the arguments given in the constructor. + * + * The most specific method according to the JLS(15.11) is used when + * there are multiple methods with the same name. + * + * Execute performs some special handling for methods and + * parameters: + * + * Static methods can be executed by providing the class as a + * target. + * + * The method name new is reserved to call the constructor + * new() will construct an object and return it. Not useful unless + * an expression :-) + * + * 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. + * + * 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. + * + * 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. + * + * @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. For + // example, if c is Integer, Integer.TYPE is returned. + private Class unwrap(Class c) + { + for (int i = 0; i < wrappers.length; i++) + if (c == wrappers[i]) + return natives[i]; + return null; + } + + // Return true if all args can be assigned to params, false + // otherwise. Arrays are guaranteed to be the same length. + private boolean compatible(Class[] params, Class[] args) + { + for (int i = 0; i < params.length; i++) + { + // 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; + } + + /** + * Return true if the method arguments in first are more specific + * than the method arguments in second, i.e. all args in first can + * be assigned to those in second. + * + * 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. + * + * @param first a Class[] value + * @param second a Class[] value + * @return a boolean 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]; + for (int i = 0; i < args.length; i++) + argTypes[i] = args[i].getClass(); + + 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(); + System.out.println("ptypeslen = " + ptypes.length); + System.out.println("ptypes = " + ptypes); + System.out.println("ctor = " + ctors[i].getName()); + for (int j=0; j < ptypes.length; j++) { + System.out.println("param = " + ptypes[i].getName()); + + } + + + 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()); + return method.invoke(target, args); + } + + + + /** 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; } + + /** Return a string representation. */ + public String toString() + { + String result = target.getClass().getName() + "." + methodName + "("; + String sep = ""; + for (int i = 0; i < arguments.length; i++) + { + result = result + sep + arguments[i].getClass().getName(); + sep = ", "; + } + result = result + ")"; + return result; + } +} diff --git a/libjava/classpath/java/beans/TODO b/libjava/classpath/java/beans/TODO new file mode 100644 index 00000000000..08e1d25ee5f --- /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 00000000000..5107954b033 --- /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 after 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. + * + *

Note: 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 00000000000..56ca5a38c7f --- /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 VetoableChangeListener - + * 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 00000000000..dce8dffd341 --- /dev/null +++ b/libjava/classpath/java/beans/VetoableChangeSupport.java @@ -0,0 +1,530 @@ +/* VetoableChangeSupport.java -- support to manage vetoable change listeners + Copyright (C) 1998, 1999, 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.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 children 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, n adds with the same listener will + * result in n events being sent to that listener for every + * vetoable change. Adding a null listener may cause a NullPointerException + * down the road. This method will unwrap a VetoableChangeListenerProxy, + * registering the underlying delegate to the named property list. + * + * @param l the listener to add + */ + public synchronized void addVetoableChangeListener(VetoableChangeListener l) + { + 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 add() has been called multiple times for a + * particular listener, remove() 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 + * VetoableChangeListenerProxy, 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, n adds on a particular + * property for a particular listener will result in n 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. Adding a null + * listener may cause a NullPointerException down the road. 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 + * @throws NullPointerException if propertyName is null + */ + public synchronized void addVetoableChangeListener(String propertyName, + VetoableChangeListener l) + { + 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 add() has been called multiple times for a particular + * listener on a property, remove() 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, + new Integer(oldVal), + new Integer(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 true 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 00000000000..428f3a2073b --- /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. + *

+ * + * 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 permitted 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 00000000000..238fd6bed91 --- /dev/null +++ b/libjava/classpath/java/beans/XMLDecoder.java @@ -0,0 +1,307 @@ +/* java.beans.XMLDecoder -- + 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.decoder.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 + * this DTD + * and creates objects according to the content. Usually such data is generated using the + * {@link XMLEncoder} class. + *

+ * An example XML document might look like this: + * + * <java> + * <string>Hello World</string> + * <int>200</int> + * </java> + * + *

To read the String and the Integer instance the following can be used (assume + * the XML data can be obtained from the InputStream):

+ * + * XMLDecoder decoder = new XMLDecoder(inputStreamContainingXMLData); + * String message = (String) decoder.readObject(); + * Integer number = (Integer) decoder.readObject(); + * + *

Besides this basic functionality the XMLDecoder has some more features that might come + * handy in certain situations:

+ *

An owner object can be set using the setOwner 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):

+ * + * <java> + * <void method="getOwner"> + * <void method="setVisible"> + * <boolean>true<boolean> + * </void> + * </void> + * </java> + * + * This accesses the JFrame and makes it visible using the setVisible method. + *

Please note that changing the owner after the having read the first object has no effect, + * because all object have been decoded then.

+ *

If the XMLDecoder is created with no {@link ExceptionListener} instance a default one + * is used that prints an error message to System.err 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 + * XMLDecoder provoked such exceptions because the resulting object(s) may be in an + * undesirable state.

+ *

Note that changing the ExceptionListener instance after readObject has been called + * once has no effect because the decoding is completed then.

+ *

At last one can provide a specific ClassLoader which is then used when Class + * objects are accessed. See {@link java.lang.Class#forName(String, boolean, ClassLoader)} for details + * on this.

+ *

Note: If the InputStream instance given to any of the constructors is null + * the resulting XMLDecoder will be silently (without any exception) useless. Each call + * to readObject will return null and never throws an + * ArrayIndexOutOfBoundsException.

+ * + * @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 exceptionListener ExceptionListener instance to which exception notifications are send. + * @param cl ClassLoader instance that is used for calls to Class.forName(String, boolean, ClassLoader) + * @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. + *

See the description of the {@link #readObject()} for the effect caused by close.

+ */ + 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. + *

See the description of {@link XMLDecoder} class for more information on the ExceptionListener.

+ * + * @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. + *

See the description of {@link XMLDecoder} class for more information on the owner object.

+ * + * @return The owner object of this decoder. + */ + public Object getOwner() + { + return owner; + } + + /** Returns the next available decoded object. + *

Note that the actual decoding takes place when the method is called for the first time.

+ *

If the close method was already called a NoSuchElementException + * is thrown.

+ *

If the InputStream instance used in the constructors was null this method + * will always return null itself.

+ * + * @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. + *

See the description of {@link XMLDecoder} class for more information on the ExceptionListener.

+ * + * @param listener + */ + public void setExceptionListener(ExceptionListener listener) + { + // uses a default implementation when null + if (listener == null) + { + listener = new DefaultExceptionListener(); + } + exceptionListener = listener; + } + + /** Sets the owner object which can be accessed from the parsed XML data. + *

See the description of {@link XMLDecoder} class for more information on the owner object.

+ * + * @param newOwner + */ + public void setOwner(Object newOwner) + { + owner = newOwner; + } + +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContext.java b/libjava/classpath/java/beans/beancontext/BeanContext.java new file mode 100644 index 00000000000..3d1be7fc8e9 --- /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 + * BeanContexts. + *

+ * + * Since I can't sprinkle the Collections interface + * documentation with special information for BeanContext + * implementors, I'll have to document special requirements for + * implementors of those functions here. + *

+ * + * add() or addAll(): + *
+ *

    + *
  1. + * May add any Object into the hierarchy as well as a + * BeanContextChild, BeanContext or + * BeanContextProxy object. + * This way, any Bean can be in the hierarchy. + *
  2. + *
  3. + * Must synchronize on BeanContext.globalHierarchyLock. + *
  4. + *
  5. + * Don't add the Object if it's already there (only once + * per BeanContext). + *
  6. + *
  7. + * If it is a BeanContextChild implementor, call + * setBeanContext() on it. If it's a + * BeanContextProxy implementor, call + * getBeanContextProxy().setBeanContext() on it. + * If setBeanContext() vetoes the change, back out + * all changes so far and throw IllegalStateException. + *
  8. + *
  9. + * If it (or its proxy) implements Visibility, call + * dontUseGui() or okToUseGui() on it, + * depending on whether you (the BeanContext) feel like + * allowing it to use the GUI or not. + *
  10. + *
  11. + * If it implements BeanContextChild or + * BeanContextProxy, register yourself (the + * BeanContext) as both a + * PropertyChangeListener and + * VetoableChangeListener on the "beanContext" + * property (it may also add itself on any other properties it wishes + * to). + *
  12. + *
  13. + * If it is a listener or event source that you (the + * BeanContext) are interested in, you may register + * yourself to it or register it to you. + *
  14. + *
  15. + * Fire a java.beans.beancontext.BeanContextMembershipEvent + * before exiting. addAll() 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. + *
  16. + *
+ *

+ * + * remove() or removeAll(): + *
+ *

    + *
  1. + * Must synchronize on BeanContext.globalHierarchyLock. + *
  2. + *
  3. + * If the specified Object is not a child of this + * BeanContext, just exit without performing any actions. + *
  4. + *
  5. + * Remove the Object from your collection of children. + *
  6. + *
  7. + * If it is a BeanContextChild implementor, call + * setBeanContext(null) on it. If it's a + * BeanContextProxy implementor, call + * getBeanContextProxy().setBeanContext(null) on it. + * If setBeanContext() vetoes the change, back out + * all changes so far and throw IllegalStateException. + *
  8. + *
  9. + * If you registered the Object to listen to you or + * registered yourself as a listener on the Object during + * add() or addAll(), undo the registration + * bycalling the appropriate removeListener() method. + *
  10. + *
  11. + * Fire a java.beans.beancontext.BeanContextMembershipEvent + * before exiting. removeAll() 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. + *
  12. + *
+ *

+ * + * addAll(), removeAll(), + * retainAll() and clear() do not need to be + * implemented, but may be if so desired. + *

+ * + * Similarly, Visibility and DesignMode methods + * should propagate changed values to children that implement interfaces + * of the same name. + *

+ * + * 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. + *

+ * + * Methods that must (or do) synchronize on the global lock: + *
+ *

    + *
  • + * Implementors of BeanContext.add() and addAll() + *
  • + *
+ * @fixme fill in the rest of the methods which use the global lock. + */ + Object globalHierarchyLock = new Object(); + + /** + * Instantiate a Bean using this Bean's ClassLoader + * and this BeanContext as the parent. + *

+ * + * This method exists mainly so that BeanContext + * 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.lang.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 BeanContext will typically + * call ClassLoader.getResource(), but may do it any + * way it wants to. This allows a BeanContext to + * have its own set of resources separate from the rest of the + * system. + *

+ * + * Beans should call this method on their parent rather than the + * associated ClassLoader method. + *

+ * + * I am assuming, but am not entirely sure, that if a + * BeanContext cannot find a resource, its + * responsibility is to call the getResource method + * of its parent BeanContext. + * + * @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 BeanContext will + * typically call ClassLoader.getResourceAsStream(), + * but may do it any way it wants to. This allows a + * BeanContext's children to have their own set of + * resources separate from the rest of the system. + *

+ * + * Beans should call this method on their parent rather than the + * associated ClassLoader method. + *

+ * + * I am assuming, but am not entirely sure, that if a + * BeanContext cannot find a resource, its + * responsibility is to call the getResourceAsStream + * method of its parent BeanContext. + * + * @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 + * BeanContext object. + * @param listener the listener to add. + */ + void addBeanContextMembershipListener(BeanContextMembershipListener listener); + + /** + * Remove a listener on changes to the membership of this + * BeanContext 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 00000000000..d1115efac85 --- /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. + *

+ * + * The difference between a BeanContext and a + * BeanContextChild, mainly, is that a + * BeanContext may be a parent. + *

+ * + * BeanContextChild 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 BeanContext, to any of the other + * BeanContexts in the tree, or to any resources obtained + * via the BeanContextServices interface. One way to do this + * is to mark any fields that contain such references as + * transient. Another way is to use a custom serializer. + *

+ * + * If you do not do this, when the BeanContext is serialized, + * all the other BeanContexts and other unnecessary things + * will be serialized along with it. + *

+ * + * Before dying, a BeanContextChild should call + * getBeanContext().remove(this) 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 BeanContext. + *

+ * + * This method is called from BeanContext.add() and + * should not be called directly. + *

+ * + * When this Object is being added to a new BeanContext or moved + * from an old one, a non-null value will be passed in. + *

+ * + * When this Object is being removed from the current + * BeanContext, setBeanContext() will + * receive the parameter null. + *

+ * + * When being removed from the current BeanContext, + * it is the BeanContextChild's responsibility to + * release all services it has obtained. + *

+ * + * This change should generate PropertyChangeEvent + * and VetoableChangeEvents 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 + * BeanContextChild, who has registered himself with + * you, will have a chance to remove this child from its + * collection. + *

+ * + * If the Bean does not wish to change the parent or be removed + * from one, it may throw the PropertyVetoException. + * If you veto a setBeanContext(null) call, then you + * should try your hardest to remedy whatever problem is keeping + * you from being removed from the BeanContext so + * that you can not veto it the next time. + * Otherwise, nasty pathological recursion stuff could occur in + * certain situations. + *

+ * + * 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. + *

+ * + * This method is called from BeanContext.add() and + * should not be called directly. + * + * @param parent the new parent for the BeanContextChild, + * or null to signify removal from a tree. + * @exception PropertyVetoException if the + * BeanContextChild implementor does not + * wish to have its parent changed. + */ + void setBeanContext(BeanContext parent) + throws PropertyVetoException; + + /** + * Get the parent BeanContext. + * @return the parent BeanContext. + */ + 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 00000000000..a8d6e34045e --- /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 BeanContextChilds which wish to associate an + * AWT component with them. The proxy is provided because the + * addPropertyChangeListener() method would conflict with + * Component if you tried to extend. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextChildComponentProxy { + /** + * Get the Component associated with this BeanContextChild. + * @return the Component associated with this + * BeanContextChild. + */ + 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 00000000000..4444ad71377 --- /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 BeanContextChild. + * This class contains the most common implementations of the methods in + * the BeanContextChild + * + * @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 set actions. + * This is here so that this class can be used as a peer. + *

+ * + * When extending this class, this variable will be set to + * this. + */ + public BeanContextChild beanContextChildPeer; + + /** + * The parent BeanContext. + */ + protected transient BeanContext beanContext; + + /** + * If setBeanContext() was vetoed once before, this + * is set to true 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 BeanContextChildSupport with itself as the peer. + * This is meant to be used when you subclass + * BeanContextChildSupport to create your child. + */ + public BeanContextChildSupport() + { + this (null); + } + + /** + * Create a new BeanContextChildSupport with the specified peer. + * @param peer the peer to use, or null to specify + * this. + */ + public BeanContextChildSupport (BeanContextChild peer) + { + if (peer == null) + { + peer = this; + } + + beanContextChildPeer = peer; + pcSupport = new PropertyChangeSupport (peer); + vcSupport = new VetoableChangeSupport (peer); + } + + /** + * Set the parent BeanContext. + *

+ * + * When this Object is being added to a new BeanContext or moved + * from an old one, a non-null value will be passed in. + *

+ * + * When this Object is being removed from the current + * BeanContext, setBeanContext() will + * receive the parameter null. + *

+ * + * Order of events: + *

    + *
  1. + * If the new BeanContext is the same as the old + * one, nothing happens. + *
  2. + *
  3. + * If the change has not been rejected or vetoed before, call + * validatePendingSetBeanContext(). If this call + * returns false, the change is rejected and a + * PropertyVetoException is thrown. + *
  4. + *
  5. + * If the change has not been rejected or vetoed before, + * VetoableChangeEvents are fired with the name + * "beanContext", using the + * fireVetoableChange() method. If a veto + * occurs, reversion events are fired using the same method, + * the change is rejected, and the veto is rethrown. + *
  6. + *
  7. + * releaseBeanContextResources() is called. + *
  8. + *
  9. + * The change is made. + *
  10. + *
  11. + * PropertyChangeEvents are fired using the + * firePropertyChange() method. + *
  12. + *
  13. + * initializeBeanContextResources() is called. + *
  14. + *
+ *

+ * + * @param newBeanContext the new parent for the + * BeanContextChild, or null to + * signify removal from a tree. + * @exception PropertyVetoException if the + * BeanContextChild 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 BeanContext. + * @return the parent BeanContext. + */ + public BeanContext getBeanContext() + { + return beanContext; + } + + /** + * Get the peer (or this if there is no peer). + * @return the peer, or this if there is no peer. + */ + public BeanContextChild getBeanContextChildPeer() { + return beanContextChildPeer; + } + + /** + * Determine whether there is a peer. + * This is true iff getBeanContextChildPeer() == this. + * @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 BeanContextServices.revokeService() 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. + * getService() will no longer work on the specified + * service class after this event has been fired. + *

+ * + * This method is meant to be overriden. + * BeanContextChildSupport'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 BeanContextServices whenever a service is made available. + *

+ * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation does + * nothing. + * + * @param event the service revoked event, with useful information + * about the new service. + */ + public void serviceAvailable(BeanContextServiceAvailableEvent event) { + } + + /** + * Called by setBeanContext() to determine whether the set should be rejected. + *

+ * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation simply + * returns true. + * + * @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 setBeanContext() to release resources of a what will soon no longer be the parent. + *

+ * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation does + * nothing. + */ + protected void releaseBeanContextResources() { + } + + /** + * Called by setBeanContext() to grab resources when the parent has been set. + *

+ * + * This method is meant to be overriden. + * BeanContextChildSupport'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 00000000000..3df91038bfe --- /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 BeanContexts which wish to associate an + * AWT container with them. The proxy is provided because the + * addPropertyChangeListener() and add() methods + * would conflict with Component and Container + * if you tried to extend. + * + * @specnote It is unclear whether anything besides BeanContexts + * are allowed to implement this interface. + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextContainerProxy { + /** + * Get the Container associated with this BeanContext. + * @return the Container associated with this + * BeanContext. + */ + 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 00000000000..f326541b034 --- /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 BeanContexts. + * + * @author John Keiser + * @since 1.2 + */ + +public abstract class BeanContextEvent extends EventObject +{ + private static final long serialVersionUID = 7267998073569045052L; + + /** + * The BeanContext that most recently passed this + * event on. + */ + protected BeanContext propagatedFrom; + + /** + * Create a new event, from the specified BeanContext. + * propagatedFrom will be initialized to + * null. + * + * @param source the source of the event. + */ + protected BeanContextEvent(BeanContext source) + { + super(source); + } + + /** + * Get the BeanContext 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 null, 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 true iff getPropagatedFrom() != null. + */ + 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 00000000000..31765426622 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java @@ -0,0 +1,112 @@ +/* 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 BeanContext. + * 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 { + /** + * 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 Object is one of the children added or removed. + * @param child the child to check. + * @return whether the Object 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 00000000000..d39c36c4b12 --- /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 BeanContextMembershipEvents are sent. + * This happens when children are added to or removed from a + * BeanContext. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextMembershipListener extends EventListener { + /** + * When beans are added to a BeanContext, + * 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 BeanContext, + * 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 00000000000..49dd7a77f30 --- /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 BeanContextChild or BeanContext associated with them + * but do not wish to implement those interfaces directly, can implement this interface. + *

+ * + * Don't shoot yourself in the foot: if you already implement + * BeanContextChild, directly or indirectly, the whole + * workings of this package will be unpredictable because it is + * indeterminate as to whether the BeanContextChild is used + * in preference to its proxy or vice versa. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextProxy { + /** + * Return the BeanContextChild associated with this + * Object. + * + * @return the BeanContextChild associated with this + * Object. + */ + 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 00000000000..eea10f261b6 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java @@ -0,0 +1,95 @@ +/* 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 BeanContextServices. + * + * @author John Keiser + * @since JDK1.2 + * @see java.beans.beancontext.BeanContextServicesListener + */ + +public class BeanContextServiceAvailableEvent extends BeanContextEvent { + /** + * The Class representing the service which is now + * available. + */ + protected Class serviceClass; + + /** + * Create a new service available event. + * @param services the BeanContextServices 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 getSourceAsBeanContextServices().getCurrentServiceSelectors(getServiceClass()) + * @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 BeanContextServices through which the new service is available. + * @return the BeanContextServices 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 00000000000..c09b5815fd7 --- /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. + *

+ * + * It is the BeanContextServiceProvider's responsibility to + * register itself with whatever BeanContextServices object + * it wishes to provide services through using the + * addService() method. + *

+ * + * If for some reason it can no longer provide services for a particular + * class, this class must invoke + * BeanContextServices.revokeService(serviceClass,this,true) + * for all the places it has registered the service. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextServiceProvider { + /** + * Get a service. + * Called from BeanContextServices.getService(). + * + *

If the requested service class is not available, or if this + * BeanContextServiceProvider chooses not honor the + * request for some reason, then this method will return + * null.

+ * + * This method may throw unchecked exceptions, so watch out. + * + * @param services the BeanContextServices 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 Class of the service being + * requested. + * @param serviceSelector a parameter to customize the service + * returned with. + * @return an instance of serviceClass (such that + * instanceof serviceClass is true), or + * null. + * @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. + *

+ * + * Called by BeanContextServices.releaseService(). + *

+ * + * Most BeanContextServiceProviders won't have to do + * anything here. + * + * @param services the BeanContextServices 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 + * BeanContextServices.getCurrentServiceSelectors(). + *

+ * + * If the specified service class does not have a finite number of + * valid service selectors, it should return null. + * If it takes a general Integer parameter, for + * example, you may as well return null or the poor + * soul who called this method will be iterating all day. + *

+ * + * If it has no valid service selectors, it should still return an empty + * Iterator. + * + * @param services the BeanContextServices 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 null. + * @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 00000000000..690b94e2cc7 --- /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; + +/** + * BeanContextServiceProviders implement this to provide information about all of the services they provide. + *

+ * + * 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 BeanInfos for all of the service classes of this BeanInfoServiceProvider. + * @return BeanInfos 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 00000000000..dfa2b89b3ae --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java @@ -0,0 +1,110 @@ +/* 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 BeanContextServices. + * + * @author John Keiser + * @since JDK1.2 + * @see java.beans.beancontext.BeanContextServiceRevokedListener + */ + +public class BeanContextServiceRevokedEvent extends BeanContextEvent { + /** + * The Class representing the service which is now + * available. + */ + protected Class serviceClass; + private boolean invalidateRefs; + + /** + * Create a new service revoked event. + * @param services the BeanContextServices 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 getServiceClass().equals(c). + * @param c the class to compare. + * @return whether the clases are equal. + */ + public boolean isServiceClass(Class c) { + return serviceClass.equals(c); + } + + /** + * Get the BeanContextServices through which the service was available. + * @return the BeanContextServices 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 00000000000..101e6e191b0 --- /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 BeanContextServices.revokeService() 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. + * getService() 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 00000000000..cb1950360af --- /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 BeanContext to provide services to its children. + * + * @specnote it is unclear whether a BeanContextServices + * 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. + *

+ * + * If revokeNow is false, the only + * effect of this method is to make all subsequent calls to + * getService() on this service class fail. + *

+ * + * If it is true, 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. + *

+ * + * If all copies of the service's class have been relinquished by + * the requestor, the BeanContextServiceRevokedListener + * previously registered by getService() will be + * unregistered. + * + * @param requestorChild the original BeanContextChild + * 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 BeanContextServices. + *

+ * + * 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. + *

+ * + * The listener will be unregistered when all services that were + * obtained by that requestor for that service class are released. + *

+ * + * If the requested service class is not available, or if this + * BeanContextServices object chooses not honor the + * request because the service class has been revoked or for some + * other reason, then this method will return null. + *

+ * + * This method may throw unchecked exceptions, so watch out. + * + * @specnote it is not specified what happens when two subsequent + * calls are made to getService() with the + * same requestor object and service class but different + * listeners. Which listener is to be notified? + * + * @param requestorChild the BeanContextChild + * associated with the requestor. Typically this will be + * the same as the requestor itself, but since any + * Object, 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 Class 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 serviceClass (such that + * instanceof serviceClass is true), or + * null. + */ + Object getService (BeanContextChild requestorChild, Object requestor, + Class serviceClass, Object serviceSelector, + BeanContextServiceRevokedListener listener) + throws TooManyListenersException; + + /** + * Get a list of all service classes supported. + *

+ * + * This method must synchronize on + * BeanContext.globalHierarchyLock. + * + * @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. + *

+ * + * If the specified service class does not have a finite number of + * valid service selectors, it should return null. + * If it takes a general Integer parameter, for + * example, you may as well return null or the poor + * soul who called this method will be iterating all day. + *

+ * + * If it has no valid service selectors, it should still return an empty + * Iterator. + * + * @param serviceClass the service class to get selectors for. + * @return a list of valid service selectors for the service + * class, or null. + */ + 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 true. + * + * @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 + * getService(). + * @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 00000000000..becc7cdb6e4 --- /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 BeanContextServices 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 00000000000..b7c4a49d8a9 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java @@ -0,0 +1,300 @@ +/* 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.Iterator; +import java.util.Locale; +import java.util.TooManyListenersException; + +/** + * @author Michael Koch + * @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 = -6848044915271367103L; + } + + protected class BCSSProxyServiceProvider + implements BeanContextServiceProvider, + BeanContextServiceRevokedListener + { + private static final long serialVersionUID = 7078212910685744490L; + + public Iterator getCurrentServiceSelectors (BeanContextServices bcs, + Class serviceClass) + { + throw new Error ("Not implemented"); + } + + public Object getService (BeanContextServices bcs, + Object requestor, + Class serviceClass, + Object serviceSelector) + { + throw new Error ("Not implemented"); + } + + public void releaseService (BeanContextServices bcs, + Object requestor, + Object service) + { + throw new Error ("Not implemented"); + } + + public void serviceRevoked (BeanContextServiceRevokedEvent bcsre) + { + throw new Error ("Not implemented"); + } + } + + protected static class BCSSServiceProvider + implements Serializable + { + private static final long serialVersionUID = 861278251667444782L; + + protected BeanContextServiceProvider serviceProvider; + + protected BeanContextServiceProvider getServiceProvider() + { + return serviceProvider; + } + } + + protected transient ArrayList bcsListeners; + + protected transient BCSSProxyServiceProvider proxy; + + protected transient int serializable; + + protected transient HashMap services; + + public BeanContextServicesSupport () + { + super(); + } + + public BeanContextServicesSupport (BeanContextServices peer) + { + super(peer); + } + + public BeanContextServicesSupport(BeanContextServices peer, Locale locale) + { + super(peer, locale); + } + + public BeanContextServicesSupport(BeanContextServices peer, Locale locale, + boolean dtime) + { + super(peer, locale, dtime); + } + + public BeanContextServicesSupport(BeanContextServices peer, Locale locale, + boolean dtime, boolean visible) + { + super(peer, locale, dtime, visible); + } + + public void addBeanContextServicesListener + (BeanContextServicesListener listener) + { + if (! bcsListeners.contains(listener)) + bcsListeners.add(listener); + } + + public boolean addService (Class serviceClass, BeanContextServiceProvider bcsp) + { + throw new Error ("Not implemented"); + } + + protected boolean addService (Class serviceClass, + BeanContextServiceProvider bcsp, + boolean fireEvent) + { + throw new Error ("Not implemented"); + } + + protected void bcsPreDeserializationHook (ObjectInputStream ois) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + protected void bcsPreSerializationHook (ObjectOutputStream oos) + throws IOException + { + throw new Error ("Not implemented"); + } + + protected void childJustRemovedHook (Object child, + BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, + Object peer) + { + throw new Error ("Not implemented"); + } + + protected BeanContextServicesSupport.BCSSServiceProvider + createBCSSServiceProvider (Class sc, BeanContextServiceProvider bcsp) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceAdded (Class serviceClass) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceRevoked (Class serviceClass, + boolean revokeNow) + { + throw new Error ("Not implemented"); + } + + public BeanContextServices getBeanContextServicesPeer () + { + throw new Error ("Not implemented"); + } + + protected static final BeanContextServicesListener + getChildBeanContextServicesListener (Object child) + { + throw new Error ("Not implemented"); + } + + public Iterator getCurrentServiceClasses () + { + throw new Error ("Not implemented"); + } + + public Iterator getCurrentServiceSelectors (Class serviceClass) + { + throw new Error ("Not implemented"); + } + + public Object getService (BeanContextChild child, Object requestor, + Class serviceClass, Object serviceSelector, + BeanContextServiceRevokedListener bcsrl) + throws TooManyListenersException + { + throw new Error ("Not implemented"); + } + + public boolean hasService (Class serviceClass) + { + throw new Error ("Not implemented"); + } + + public void initialize () + { + super.initialize(); + + bcsListeners = new ArrayList(); + services = new HashMap(); + } + + protected void initializeBeanContextResources () + { + throw new Error ("Not implemented"); + } + + protected void releaseBeanContextResources () + { + throw new Error ("Not implemented"); + } + + public void releaseService (BeanContextChild child, Object requestor, + Object service) + { + throw new Error ("Not implemented"); + } + + public void removeBeanContextServicesListener + (BeanContextServicesListener listener) + { + int index = bcsListeners.indexOf(listener); + + if (index > -1) + bcsListeners.remove(index); + } + + public void revokeService (Class serviceClass, BeanContextServiceProvider bcsp, + boolean revokeCurrentServicesNow) + { + throw new Error ("Not implemented"); + } + + public void serviceAvailable (BeanContextServiceAvailableEvent bcssae) + { + throw new Error ("Not implemented"); + } + + public void serviceRevoked (BeanContextServiceRevokedEvent bcssre) + { + throw new Error ("Not implemented"); + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextSupport.java new file mode 100644 index 00000000000..7e024e23a13 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextSupport.java @@ -0,0 +1,460 @@ +/* BeanContextSupport.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.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.Locale; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class BeanContextSupport extends BeanContextChildSupport + implements BeanContext, Serializable, PropertyChangeListener, + VetoableChangeListener +{ + private static final long serialVersionUID = -4879613978649577204L; + + private void readObject (ObjectInputStream s) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + private void writeObject (ObjectOutputStream s) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + protected class BCSChild implements Serializable + { + private static final long serialVersionUID = 3289144128843950629L; + } + + protected static final class BCSIterator implements Iterator + { + public boolean hasNext () + { + throw new Error ("Not implemented"); + } + + public Object next () + { + throw new Error ("Not implemented"); + } + + 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; + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport () + { + this (null, null, true, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer) + { + this (peer, null, true, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer, Locale lcle) + { + this (peer, lcle, true, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer, Locale lcle, boolean dtime) + { + this (peer, lcle, dtime, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer, Locale lcle, boolean dtime, + boolean visible) + { + locale = lcle; + designTime = dtime; + okToUseGui = visible; + + initialize (); + } + + public boolean add (Object targetChild) + { + if (targetChild == null) + throw new IllegalArgumentException(); + + if (children.containsKey(targetChild)) + return false; + + // FIXME: The second argument is surely wrong. + children.put(targetChild, targetChild); + return true; + } + + public boolean addAll (Collection c) + { + throw new UnsupportedOperationException(); + } + + public void addBeanContextMembershipListener + (BeanContextMembershipListener listener) + { + if (! bcmListeners.contains(listener)) + bcmListeners.add(listener); + } + + public boolean avoidingGui () + { + throw new Error ("Not implemented"); + } + + protected Iterator bcsChildren () + { + throw new Error ("Not implemented"); + } + + protected void bcsPreDeserializationHook (ObjectInputStream ois) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + protected void bcsPreSerializationHook (ObjectOutputStream oos) + throws IOException + { + throw new Error ("Not implemented"); + } + + protected void childDeserializedHook (Object child, BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected void childJustAddedHook (Object child, BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected void childJustRemovedHook (Object child, BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected static final boolean classEquals (Class first, Class second) + { + throw new Error ("Not implemented"); + } + + public void clear () + { + throw new UnsupportedOperationException(); + } + + public boolean contains (Object o) + { + throw new Error ("Not implemented"); + } + + public boolean containsAll (Collection c) + { + throw new Error ("Not implemented"); + } + + public boolean containsKey (Object o) + { + throw new Error ("Not implemented"); + } + + protected final Object[] copyChildren () + { + throw new Error ("Not implemented"); + } + + protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, Object peer) + { + throw new Error ("Not implemented"); + } + + protected final void deserialize (ObjectInputStream ois, Collection coll) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + public void dontUseGui () + { + throw new Error ("Not implemented"); + } + + protected final void fireChildrenAdded (BeanContextMembershipEvent bcme) + { + throw new Error ("Not implemented"); + } + + protected final void fireChildrenRemoved (BeanContextMembershipEvent bcme) + { + throw new Error ("Not implemented"); + } + + public BeanContext getBeanContextPeer () + { + throw new Error ("Not implemented"); + } + + protected static final BeanContextChild getChildBeanContextChild (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final BeanContextMembershipListener getChildBeanContextMembershipListener (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final PropertyChangeListener getChildPropertyChangeListener (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final Serializable getChildSerializable (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final VetoableChangeListener getChildVetoableChangeListener (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final Visibility getChildVisibility (Object child) + { + throw new Error ("Not implemented"); + } + + public Locale getLocale () + { + return locale; + } + + public URL getResource (String name, BeanContextChild bcc) + { + throw new Error ("Not implemented"); + } + + public InputStream getResourceAsStream (String name, BeanContextChild bcc) + { + throw new Error ("Not implemented"); + } + + protected void initialize () + { + bcmListeners = new ArrayList(); + children = new HashMap(); + } + + public Object instantiateChild (String beanName) + throws IOException, ClassNotFoundException + { + throw new Error ("Not implemented"); + } + + public boolean isDesignTime () + { + throw new Error ("Not implemented"); + } + + public boolean isEmpty () + { + throw new Error ("Not implemented"); + } + + public boolean isSerializing () + { + throw new Error ("Not implemented"); + } + + public Iterator iterator () + { + return children.keySet().iterator(); + } + + public boolean needsGui () + { + throw new Error ("Not implemented"); + } + + public void okToUseGui () + { + throw new Error ("Not implemented"); + } + + public void propertyChange (PropertyChangeEvent pce) + { + throw new Error ("Not implemented"); + } + + public final void readChildren (ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + throw new Error ("Not implemented"); + } + + public boolean remove (Object targetChild) + { + return remove(targetChild, true); + } + + protected boolean remove (Object targetChild, boolean callChildSetBC) + { + if (targetChild == null) + throw new IllegalArgumentException(); + + throw new Error ("Not implemented"); + } + + public boolean removeAll (Collection c) + { + throw new UnsupportedOperationException(); + } + + public void removeBeanContextMembershipListener (BeanContextMembershipListener bcml) + { + throw new Error ("Not implemented"); + } + + public boolean retainAll (Collection c) + { + throw new UnsupportedOperationException(); + } + + protected final void serialize (ObjectOutputStream oos, Collection coll) + throws IOException + { + throw new Error ("Not implemented"); + } + + public void setDesignTime (boolean dtime) + { + throw new Error ("Not implemented"); + } + + public void setLocale (Locale newLocale) + throws PropertyVetoException + { + throw new Error ("Not implemented"); + } + + public int size () + { + throw new Error ("Not implemented"); + } + + public Object[] toArray () + { + return children.keySet().toArray(); + } + + public Object[] toArray(Object[] array) + { + return children.keySet().toArray(array); + } + + protected boolean validatePendingAdd (Object targetChild) + { + throw new Error ("Not implemented"); + } + + protected boolean validatePendingRemove (Object targetChild) + { + throw new Error ("Not implemented"); + } + + public void vetoableChange (PropertyChangeEvent pce) + throws PropertyVetoException + { + throw new Error ("Not implemented"); + } + + public final void writeChildren (ObjectOutputStream oos) + throws IOException + { + throw new Error ("Not implemented"); + } +} diff --git a/libjava/classpath/java/beans/beancontext/package.html b/libjava/classpath/java/beans/beancontext/package.html new file mode 100644 index 00000000000..55e3bd723da --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.beans.beancontext + + +

Containers and execution environments for beans.

+ + + diff --git a/libjava/classpath/java/beans/package.html b/libjava/classpath/java/beans/package.html new file mode 100644 index 00000000000..5ca8000371b --- /dev/null +++ b/libjava/classpath/java/beans/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.beans + + +

Listeners and descriptors for managing beans.

+ + + -- cgit v1.2.3