You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by ky...@apache.org on 2004/12/03 03:54:10 UTC

svn commit: r109621 - in incubator/beehive/trunk/controls: src/api/org/apache/beehive/controls/api/bean src/runtime/org/apache/beehive/controls/runtime/bean src/runtime/org/apache/beehive/controls/runtime/generator test/src/controls/org/apache/beehive/controls/test/controls/property test/src/units/org/apache/beehive/controls/test/java/property

Author: kylem
Date: Thu Dec  2 18:54:09 2004
New Revision: 109621

URL: http://svn.apache.org/viewcvs?view=rev&rev=109621
Log:
Added support for bound and constrained properties in controls.   You can now annotate any
propert declaration method within an @PropertySet with @PropertyInfo(bound=true,constrained=true)
to signal that PropertyChangeListener and/or VetoableChangeListener registration methods should
be exposed.   PropertyChangeEvents will be delivered for these bound and/or constrained properties
as described in section 7.4 of the JavaBeans spec when property setters are called.  Still 
remaining to be done is a way to expose bound/constrained property change events to an 
associated ControlImplementation class, but this checkin fully enables external listeners for 
PropertyChangeEvents.  Included is a new checkin test case that validates the new functionality.


Added:
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java
Modified:
   incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java
   incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java
   incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java
   incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java
   incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
   incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm

Modified: incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java?view=diff&rev=109621&p1=incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java&r1=109620&p2=incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java&r2=109621
==============================================================================
--- incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java	(original)
+++ incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java	Thu Dec  2 18:54:09 2004
@@ -29,6 +29,8 @@
  * interface to provide a way to get the <code>BeanContext</code> directly associated
  * with the Java Control.   The <code>getBeanContext()</code> API on the interface will
  * return the parent (containing) context.
+ *
+ * @see java.beans.beancontext.BeanContextProxy
  */
 public interface ControlBean extends BeanContextProxy, java.io.Serializable
 {

Modified: incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java?view=diff&rev=109621&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java&r1=109620&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java&r2=109621
==============================================================================
--- incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java	(original)
+++ incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java	Thu Dec  2 18:54:09 2004
@@ -19,6 +19,10 @@
 
 import java.beans.beancontext.BeanContext;
 import java.beans.beancontext.BeanContextServices;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.beans.VetoableChangeSupport;
+import java.beans.VetoableChangeListener;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.lang.reflect.AnnotatedElement;
@@ -527,9 +531,6 @@
      */
     protected void setControlProperty(PropertyKey key, Object o)
     {
-        //
-        // TODO: Property change notification and veto handling go here
-        //
         _properties.setProperty(key, o);
     }
 
@@ -561,32 +562,15 @@
         return method.invoke(eventNotifier, args);
     }
 
-    //
-    // These can all be removed once auto-boxing can be assumed
-    //
-    protected void setControlProperty(PropertyKey key, int i)
-    { setControlProperty(key, new Integer(i)); }
-
-    protected void setControlProperty(PropertyKey key, short s)
-    { setControlProperty(key, new Short(s)); }
-
-    protected void setControlProperty(PropertyKey key, long l)
-    { setControlProperty(key, new Long(l)); }
-
-    protected void setControlProperty(PropertyKey key, byte b)
-    { setControlProperty(key, new Byte(b)); }
-
-    protected void setControlProperty(PropertyKey key, char c)
-    { setControlProperty(key, new Character(c)); }
-
-    protected void setControlProperty(PropertyKey key, float f)
-    { setControlProperty(key, new Float(f)); }
-
-    protected void setControlProperty(PropertyKey key, double d)
-    { setControlProperty(key, new Double(d)); }
-
-    protected void setControlProperty(PropertyKey key, boolean b)
-    { setControlProperty(key, new Boolean(b)); }
+    /**
+     * Returns a property on the ControlBean instance.   This version does not coerce
+     * an annotation type property from a PropertyMap to a proxy instance of the
+     * type.
+     */
+    protected Object getRawControlProperty(PropertyKey key)
+    {
+        return _properties.getProperty(key);
+    }
 
     /**
      * Returns a property on the ControlBean instance.  All generated property getter methods
@@ -594,7 +578,7 @@
      */
     protected Object getControlProperty(PropertyKey key)
     {
-        Object value = _properties.getProperty(key);
+        Object value = getRawControlProperty(key);
 
         // If the held value is a PropertyMap, then wrap it in an annotation proxy of
         // the expected type.
@@ -643,6 +627,67 @@
     }
 
     /**
+     * This protected version is only available to concrete subclasses that expose bound
+     * property support.   This method is synchronized to enable lazy instantiation, in
+     * the belief that is a bigger win to avoid allocating when there are no listeners
+     * than it is to introduce synchronization overhead on access.
+     */
+    synchronized protected PropertyChangeSupport getPropertyChangeSupport()
+    {
+        if (_changeSupport == null)
+            _changeSupport = new PropertyChangeSupport(this);
+
+        return _changeSupport;
+    }
+
+    /**
+     * Delivers a PropertyChangeEvent to any registered PropertyChangeListeners associated
+     * with the property referenced by the specified key.
+     *
+     * This method *should not* be synchronized, as the PropertyChangeSupport has its own
+     * built in synchronization mechanisms.
+     */
+    protected void firePropertyChange(PropertyKey propertyKey, Object oldValue, Object newValue)
+    {
+        // No change support instance means no listeners
+        if (_changeSupport == null)
+            return;
+
+        _changeSupport.firePropertyChange(propertyKey.getPropertyName(), oldValue, newValue);
+    }
+
+    /**
+     * This protected version is only available to concrete subclasses that expose bound
+     * property support.   This method is synchronized to enable lazy instantiation, in
+     * the belief that is a bigger win to avoid allocating when there are no listeners
+     * than it is to introduce synchronization overhead on access.
+     */
+    synchronized protected VetoableChangeSupport getVetoableChangeSupport()
+    {
+        if (_vetoSupport == null)
+            _vetoSupport = new VetoableChangeSupport(this);
+
+        return _vetoSupport;
+    }
+
+    /**
+     * Delivers a PropertyChangeEvent to any registered VetoableChangeListeners associated
+     * with the property referenced by the specified key.
+     *
+     * This method *should not* be synchronized, as the VetoableChangeSupport has its own
+     * built in synchronization mechanisms.
+     */
+    protected void fireVetoableChange(PropertyKey propertyKey, Object oldValue, Object newValue)
+                   throws java.beans.PropertyVetoException
+    {
+        // No veto support instance means no listeners
+        if (_vetoSupport == null)
+            return;
+
+        _vetoSupport.fireVetoableChange(propertyKey.getPropertyName(), oldValue, newValue);
+    }
+
+    /**
      * Returns the parameter names for a method on the ControlBean.  Actual mapping is done
      * by generated subclasses, so if we reach the base ControlBean implementation, then
      * no parameter names are available for the target method.
@@ -719,6 +764,16 @@
      * is threadsafe, then the value will be null.
      */
     transient private Semaphore _invokeLock;
+
+    /**
+     * This field manages PropertyChangeListeners (if supporting bound properties).
+     */
+    private PropertyChangeSupport _changeSupport;
+
+    /**
+     * This field manages VetoabbleChangeListeners (if supporting constrained properties)
+     */
+    private VetoableChangeSupport _vetoSupport;
 
     /** END synchronized fields */
 

Modified: incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java?view=diff&rev=109621&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java&r1=109620&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java&r2=109621
==============================================================================
--- incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java	(original)
+++ incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java	Thu Dec  2 18:54:09 2004
@@ -246,13 +246,29 @@
                         new AptPropertySet(this, (AnnotationTypeDeclaration)innerDecl, _env));
             }
         }
+
+        //
+        // Detect the presence of locally declared bound or constrained properties
+        //
+        for (AptPropertySet propSet : propSets)
+        {
+            for (AptProperty prop : propSet.getProperties())
+            {
+                if (prop.isBound())
+                    _hasBoundProperties = true;
+
+                if (prop.isConstrained())
+                    _hasConstrainedProperties = true;
+            }
+        }
+
         return propSets;
     }
 
     /**
      * Returns the list of PropertySets declared directly by this AptControlInterface
      */
-    public ArrayList<AptPropertySet> getPropertySets() { return _propertySets; }
+    public Collection<AptPropertySet> getPropertySets() { return _propertySets; }
 
     /**
      * Returns the total number of properties for this control interface
@@ -267,25 +283,59 @@
     }
 
     /**
-     * Returns true if the control BeanInfo needs a customized set of PropertyDescriptors
-     * code generated or false if standard introspection via reflection is ok.
+     * Returns true if the interface has any bound properties associated with it.
      */
-    public boolean needsCustomPropertyDescriptors()
+    public boolean hasBoundProperties()
+    {
+        if (_superClass != null && _superClass.hasBoundProperties())
+            return true;
+
+        return _hasBoundProperties;
+    }
+
+    /**
+     * Returns true if this interface is the first interface in the inheritance hierarchy
+     * to declare support for bound properties.  This is used to declared PropertyChangeListener
+     * registration methods for the bean once (and only once).
+     */
+    public boolean addsBoundPropertySupport()
     {
         //
-        // The algorithm here is pretty simple.. if any individual property needs a customized
-        // descriptor, then you have to generate them all.  Reflection-driven introspection is
-        // an all-or-nothing deal as implemented by java.beans.Introspector.
+        // If a super interface has already added support, then not added here
         //
-        for (AptPropertySet propertySet : _propertySets)
-        {
-            for (AptProperty property : propertySet.getProperties())
-            {
-                if (property.needsCustomPropertyDescriptor())
-                    return true;
-            }
-        }
-        return false;
+        if (_superClass != null && _superClass.addsBoundPropertySupport())
+            return false;
+
+        return hasBoundProperties();
+    }
+
+    /**
+     * Returns true if any properties declared directly by this control interface are constrained
+     * properties.  This <b>will not</b> reflect the attributes of properties declared on
+     * an interface from which this interface derives.
+     */
+    public boolean hasConstrainedProperties()
+    {
+        if (_superClass != null && _superClass.hasConstrainedProperties())
+            return true;
+
+        return _hasConstrainedProperties;
+    }
+
+    /**
+     * Returns true if this interface is the first interface in the inheritance hierarchy
+     * to declare support for constrained properties.  This is used to declared 
+     * VetoableChangeListener registration methods for the bean once (and only once).
+     */
+    public boolean addsConstrainedPropertySupport()
+    {
+        //
+        // If a super interface has already added support, then not added here
+        //
+        if (_superClass != null && _superClass.addsConstrainedPropertySupport())
+            return false;
+
+        return hasConstrainedProperties();
     }
 
     /**
@@ -609,6 +659,8 @@
     private AptControlInterface    _superClass;
     AptMethodSet<AptOperation>     _operations;
     ArrayList<AptPropertySet>      _propertySets;
+    boolean                        _hasBoundProperties;
+    boolean                        _hasConstrainedProperties;;
     ArrayList<AptEventSet>         _eventSets;
     ControlBean                    _bean;
     FeatureInfo                    _featureInfo;

Modified: incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java?view=diff&rev=109621&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java&r1=109620&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java&r2=109621
==============================================================================
--- incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java	(original)
+++ incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java	Thu Dec  2 18:54:09 2004
@@ -71,26 +71,29 @@
      * Returns the base property name. The associated accessor methods will have the
      * form set{name} and get{name}
      */
-    public String getName()
+    public String getAccessorName()
     {
         StringBuffer sb = new StringBuffer();
         sb.append(_propertySet.getPrefix());
     
-        String memberName = getMemberName();
-        sb.append(Character.toUpperCase(memberName.charAt(0)));
-        if (memberName.length() > 0)
-            sb.append(memberName.substring(1));
+        String name = getName();
+        sb.append(Character.toUpperCase(name.charAt(0)));
+        if (name.length() > 0)
+            sb.append(name.substring(1));
         return sb.toString();
     }
 
     /**
-     * Returns the member name associated with this Property in the PropertySet
+     * Returns the name associated with this Property in the PropertySet
      */
-    public String getMemberName()
+    public String getName()
     {
         if ( _propDecl == null )
             return "";
 
+        //
+        // Use the member name of the property method in the property set
+        //
         return _propDecl.getSimpleName();
     }
 
@@ -99,15 +102,7 @@
      */
     public String getKeyName()
     {
-        return getName() + "Key";
-    }
-
-    /**
-     * Returns true if the property needs a custom-generated PropertyDescriptor, false otherwise
-     */
-    public boolean needsCustomPropertyDescriptor()
-    {
-        return getPropertyInfo() != null || getFeatureInfo() != null;
+        return getAccessorName() + "Key";
     }
 
     /**
@@ -144,6 +139,41 @@
     }
 
     /**
+     * Returns any FeatureInfo associated with the property (or null if none)
+     */ 
+    public FeatureInfo getFeatureInfo()
+    {
+        if ( _propDecl == null )
+            return null;
+        
+        return _propDecl.getAnnotation(FeatureInfo.class);
+    }
+
+    /**
+     * Returns 'true' is the property is a bound property that will support registration of
+     * a PropertyChangeListener for change notifications.
+     */
+    public boolean isBound()
+    {
+        //
+        // Constrained properties are implicitly bound.  Refer to section 7.4.3 of the JavaBeans
+        // spec for the rationale.
+        //
+        PropertyInfo propInfo = getPropertyInfo();
+        return propInfo != null && (propInfo.bound() || propInfo.constrained());
+    }
+
+    /**
+     * Returns 'true' is the property is a constrained property that will support registration of
+     * a VetoableChangeListener for vetoable change notifications.
+     */
+    public boolean isConstrained()
+    {
+        PropertyInfo propInfo = getPropertyInfo();
+        return propInfo != null && propInfo.constrained();
+    }
+
+    /**
      * Returns the class name of the property editor class, or null
      */
     public String getEditorClass()
@@ -183,17 +213,6 @@
             }
         }
         return null;
-    }
-
-    /**
-     * Returns any FeatureInfo associated with the property (or null if none)
-     */ 
-    public FeatureInfo getFeatureInfo()
-    {
-        if ( _propDecl == null )
-            return null;
-        
-        return _propDecl.getAnnotation(FeatureInfo.class);
     }
 
     AnnotationTypeElementDeclaration _propDecl;

Modified: incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm?view=diff&rev=109621&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm&r1=109620&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm&r2=109621
==============================================================================
--- incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm	(original)
+++ incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm	Thu Dec  2 18:54:09 2004
@@ -167,24 +167,35 @@
 ## This macro defines the property accessor methods for a bean property
 ##
 #macro (declarePropertyAccessors $property)
-    public static PropertyKey $property.keyName = new PropertyKey(${property.propertySet.className}.class, "$property.memberName");
+    public static PropertyKey $property.keyName = new PropertyKey(${property.propertySet.className}.class, "$property.name");
 
     #if ($property.isAnnotation())
-    public void set${property.name}(PropertyMap map)
-    {
-        setControlProperty($property.keyName, map);
-    }
+    public void set${property.accessorName}(PropertyMap value)
     #else
-    public void set${property.name}($property.type prop)
+    public void set${property.accessorName}($property.type value)
+    #end
+        #if ($property.constrained)
+        throws java.beans.PropertyVetoException
+        #end
     {
-        setControlProperty($property.keyName, prop);
+
+        #if ($property.bound || $property.constrained)
+        Object oldValue = getRawControlProperty($property.keyName);
+        #end
+
+        #if ($property.constrained)
+        fireVetoableChange($property.keyName, oldValue, value);
+        #end
+        setControlProperty($property.keyName, value);
+        #if ($property.bound)
+        firePropertyChange($property.keyName, oldValue, value);
+        #end
     }
-    #end
 
     #if ($property.getType().equals("boolean"))
-    public $property.type is${property.name}()
+    public $property.type is${property.accessorName}()
     #else
-    public $property.type get${property.name}()
+    public $property.type get${property.accessorName}()
     #end
     {
         return (#toObject($property.type))getControlProperty($property.keyName);
@@ -192,6 +203,86 @@
 
 #end
 ##
+## This macro declares the registration methods supporting a PropertyChangeListener
+##
+#macro (declareBoundPropertySupport)
+    /**
+     * Adds a new PropertyChangeListener for listening to changes on bound properties of this 
+     * control.
+     */
+    public void addPropertyChangeListener(PropertyChangeListener pcl)
+    {
+        getPropertyChangeSupport().addPropertyChangeListener(pcl);
+    }
+
+    /**
+     * Adds a new PropertyChangeListener for listening to changes to a specific bound
+     * property of this control.
+     */
+    public void addPropertyChangeListener(String propertyName, PropertyChangeListener pcl)
+    {
+        getPropertyChangeSupport().addPropertyChangeListener(propertyName, pcl);
+    }
+
+    /**
+     * Removes a registered PropertyChangeListener listening to changes on bound properties of 
+     * this control.
+     */
+    public void removePropertyChangeListener(PropertyChangeListener pcl)
+    {
+        getPropertyChangeSupport().removePropertyChangeListener(pcl);
+    }
+
+    /**
+     * Removes a registered PropertyChangeListener listening to changes on a specific bound
+     * property of this control.
+     */
+    public void removePropertyChangeListener(String propertyName, PropertyChangeListener pcl)
+    {
+        getPropertyChangeSupport().removePropertyChangeListener(propertyName, pcl);
+    }
+#end
+##
+## This macro declares the registration methods supporting a VetoableChangeListener
+##
+#macro (declareConstrainedPropertySupport)
+    /**
+     * Adds a new PropertyChangeListener for listening to changes on bound properties of this 
+     * control.
+     */
+    public void addVetoableChangeListener(VetoableChangeListener vcl)
+    {
+        getVetoableChangeSupport().addVetoableChangeListener(vcl);
+    }
+
+    /**
+     * Adds a new PropertyChangeListener for listening to changes to a specific constrained
+     * property of this control.
+     */
+    public void addVetoableChangeListener(String propertyName, VetoableChangeListener vcl)
+    {
+        getVetoableChangeSupport().addVetoableChangeListener(propertyName, vcl);
+    }
+
+    /**
+     * Removes a registered PropertyChangeListener listening to changes on constrained properties 
+     * of this control.
+     */
+    public void removeVetoableChangeListener(VetoableChangeListener vcl)
+    {
+        getVetoableChangeSupport().removeVetoableChangeListener(vcl);
+    }
+
+    /**
+     * Removes a registered PropertyChangeListener listening to changes to a specific constrained
+     * property of this control.
+     */
+    public void removeVetoableChangeListener(String propertyName, VetoableChangeListener vcl)
+    {
+        getVetoableChangeSupport().removeVetoableChangeListener(propertyName, vcl);
+    }
+#end
+##
 ## This macro defines the implementation of an event routing method
 ##
 #macro (declareEventImpl $event)
@@ -276,10 +367,13 @@
 ##
 package $bean.package;
 
+import java.beans.*;
+
 import java.lang.reflect.Method;
 import java.lang.reflect.UndeclaredThrowableException;
 import java.util.HashMap;
 import java.util.Map;
+
 import org.apache.beehive.controls.api.bean.Extensible;
 import org.apache.beehive.controls.api.context.ControlBeanContext;
 import org.apache.beehive.controls.api.properties.PropertyKey;
@@ -310,6 +404,14 @@
         #foreach ($property in $propertySet.properties)
             #declarePropertyAccessors ($property)
         #end
+    #end
+
+    #if ($intf.addsBoundPropertySupport())
+    #declareBoundPropertySupport()
+    #end
+
+    #if ($intf.addsConstrainedPropertySupport())
+    #declareConstrainedPropertySupport()
     #end
 
     #foreach ($eventSet in $intf.eventSets)

Modified: incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm?view=diff&rev=109621&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm&r1=109620&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm&r2=109621
==============================================================================
--- incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm	(original)
+++ incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm	Thu Dec  2 18:54:09 2004
@@ -88,7 +88,7 @@
         return bd;
     }
 
-    #if ($intf.needsCustomPropertyDescriptors())
+    #if ($intf.propertyCount != 0)
     public PropertyDescriptor [] getPropertyDescriptors()
     {
         PropertyDescriptor [] propDescriptors = new PropertyDescriptor[$intf.propertyCount];
@@ -98,7 +98,7 @@
             PropertyDescriptor pd;
             #foreach ($propertySet in $intf.propertySets)
                 #foreach ($property in $propertySet.properties)      
-                    pd = new PropertyDescriptor("$property.memberName", ${bean.className}.class);
+                    pd = new PropertyDescriptor("$property.name", ${bean.className}.class);
                     #if ($property.propertyInfo)
                         pd.setBound($property.propertyInfo.bound());
                         pd.setConstrained($property.propertyInfo.constrained());
@@ -107,7 +107,7 @@
                         #end
                     #end
                     #if ($property.featureInfo)
-                        #initFeatureDescriptor("pd" $property.featureInfo $property.memberName)
+                        #initFeatureDescriptor("pd" $property.featureInfo $property.name)
                     #end
                     propDescriptors[i++] = pd;
                 #end

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java?view=auto&rev=109621
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java	Thu Dec  2 18:54:09 2004
@@ -0,0 +1,71 @@
+package org.apache.beehive.controls.test.controls.property;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.beans.PropertyChangeListener;
+import java.beans.VetoableChangeListener;
+
+import org.apache.beehive.controls.api.bean.ControlInterface;
+import org.apache.beehive.controls.api.packaging.PropertyInfo;
+import org.apache.beehive.controls.api.properties.PropertySet;
+import org.apache.beehive.controls.api.events.EventSet;
+
+/**
+ * A simple control that can be used for property testing of bound and constrained
+ * property event behavior.
+ */
+@ControlInterface
+public interface PropEvents
+{
+    //
+    // Declare a set of bound properties.  These should deliver PropertyChange events
+    // if modified.
+    //
+    @PropertySet
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD} )
+    public @interface BoundProps
+    {
+        @PropertyInfo(bound=true)
+        public int boundInt() default 0;
+    }
+
+    //
+    // Declare a set of bound properties.  These should deliver PropertyChange and
+    // VetoableChange events if modified.
+    //
+    @PropertySet
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD} )
+    public @interface ConstrainedProps
+    {
+        @PropertyInfo(constrained=true)
+        public int constrainedInt() default 0;
+
+    }
+
+    //
+    // Declared unbound and unconstrained events.  These should deliver no events if
+    // modified.
+    //
+    @PropertySet
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD} )
+    public @interface BasicProps
+    {
+        public int basicInt() default 0;
+    }
+
+    //
+    // These EventSets are used as an external test point for events received by the
+    // implementation class
+    //
+    //@EventSet
+    //public interface PropertyChangeOnImpl extends PropertyChangeListener {}
+
+    //@EventSet
+    //public interface VetoableChangeOnImpl extends VetoableChangeListener {}
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs?view=auto&rev=109621
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs	Thu Dec  2 18:54:09 2004
@@ -0,0 +1,16 @@
+package org.apache.beehive.controls.test.controls.property;
+
+import org.apache.beehive.controls.api.bean.ControlImplementation;
+import org.apache.beehive.controls.api.context.Context;
+import org.apache.beehive.controls.api.context.ControlBeanContext;
+
+@ControlImplementation
+public class PropEventsImpl implements PropEvents
+{ 
+    static final long serialVersionUID = 1L;
+
+    @Context
+    ControlBeanContext context;
+
+    // Does nothing (for now)
+}

Added: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java?view=auto&rev=109621
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java	Thu Dec  2 18:54:09 2004
@@ -0,0 +1,293 @@
+package org.apache.beehive.controls.test.java.property;
+
+import java.beans.Beans;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.beehive.test.tools.mantis.annotations.tch.Freq;
+
+import org.apache.beehive.controls.api.bean.ControlBean;
+import org.apache.beehive.controls.test.controls.property.PropEventsBean;
+
+/**
+ * This test case validates bound and constrained property behaviors, w.r.t. to the delivery
+ * of PropertyChange events for bound and constrained events
+ */
+@Freq("checkin")
+public class PropEvents extends TestCase
+{
+    PropEventsBean eventBean;
+
+    public PropEvents( String s ) { super( s ); }
+
+    /**
+     * This base class hold a queue of property change events and makes them accessible
+     * for event validation.
+     */
+    abstract static class QueueListener
+    {
+        QueueListener()
+        {
+            initEvents();
+        }
+
+        /**
+         * Resets/initializes the internal event queue
+         */
+        public void initEvents()
+        {
+            eventQueue = new ArrayList<PropertyChangeEvent>();
+        }
+
+        /**
+         * Returns the collection of events
+         */
+        public Collection<PropertyChangeEvent> getEvents() { return eventQueue; }
+
+        ArrayList<PropertyChangeEvent> eventQueue;
+    }
+
+    static class ChangeTestListener extends QueueListener 
+                 implements java.beans.PropertyChangeListener
+    {
+        /**
+         * Implementation of PropertyChangeListener.propertyChange().  Will enqueue
+         * the received event.
+         */
+        public void propertyChange(PropertyChangeEvent pce)
+        {
+            eventQueue.add(pce);
+        }
+    }
+
+    static class VetoableTestListener extends QueueListener
+                 implements java.beans.VetoableChangeListener
+    {
+        /**
+         * Implementation of PropertyChangeListener.propertyChange().  Will enqueue
+         * the received event.
+         */
+        public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException
+        {
+            eventQueue.add(pce);
+
+            // Veto attempts to set even values
+            if ((((Integer)pce.getNewValue()).intValue() & 1) == 0)
+                throw new PropertyVetoException("Sorry", pce);
+        }
+    }
+
+
+    public void setUp() throws Exception
+    { 
+        eventBean = (PropEventsBean)
+                Beans.instantiate(Thread.currentThread().getContextClassLoader(),
+                    "org.apache.beehive.controls.test.controls.property.PropEventsBean");
+    }
+
+    /**
+     * Basic test: setting/reading property values by a control client
+     */
+    public void testPropertyChange() throws Exception
+    {
+        // Set the test property to a well-defined initial value
+        eventBean.setBoundInt(0);
+
+        // Create a new test listener and register it on the test bean
+        ChangeTestListener ctl = new ChangeTestListener();
+        eventBean.addPropertyChangeListener(ctl);
+
+        // Call the bound property setter on the bean 100 times
+        for (int i = 1; i < 100; i++)
+            eventBean.setBoundInt(i);
+
+        // Now validate the received properties
+        int i = 0;
+        for (PropertyChangeEvent pce : ctl.getEvents())
+        {
+            if (pce.getSource() != eventBean)
+                fail("Invalid source value in PropertyChangeEvent");
+
+            if (!pce.getPropertyName().equals("boundInt"))
+                fail("Invalid property name: " + pce.getPropertyName());
+
+            if (!pce.getOldValue().equals(new Integer(i)))
+                fail("Unexpected old value: " + pce.getOldValue() + ", expected: " + i);
+
+            if (!pce.getNewValue().equals(new Integer(i+1)))
+                fail("Unexpected new value: " + pce.getNewValue() + ", expected: " + (i+1));
+
+            i++;
+        }
+        if (i != 99)
+            fail("Received less events than expected: " + i);
+
+        // Reset the event queue
+        ctl.initEvents();
+
+        // Change an unbound property and verify that no property change event was delivered
+        eventBean.setBasicInt(0);
+        if (ctl.getEvents().size() != 0)
+            fail("Unexpected event delivered on unbound property change");
+
+        // Remove the event listener, change a bound property, and verify no event is delivered
+        eventBean.removePropertyChangeListener(ctl);
+        eventBean.setBoundInt(0);
+        if (ctl.getEvents().size() != 0)
+            fail("Unexpected event delivered after listener removed");
+    }
+
+    /**
+     * Basic test: setting/reading property values by a control client
+     */
+    public void testVetoChange() throws Exception
+    {
+        // Set the test property to a well-defined initial value
+        eventBean.setConstrainedInt(0);
+
+        // Create a new test listener and register it on the test bean
+        VetoableTestListener vtl = new VetoableTestListener();
+        eventBean.addVetoableChangeListener(vtl);
+
+        // Create a change listener and register it... this will be used to validate the
+        // property changes that were not vetoed
+        ChangeTestListener ctl = new ChangeTestListener();
+        eventBean.addPropertyChangeListener(ctl);
+
+        // Call the bound property setter on the bean 100 times
+        int expected = 0;
+        for (int i = 1; i < 100; i++)
+        {
+            boolean vetoed = false;
+            boolean expectVeto = (i & 1) == 0;
+            try
+            {
+                eventBean.setConstrainedInt(i);
+            }
+            catch (PropertyVetoException pve)
+            {
+                vetoed = true;
+            }
+
+            if (vetoed)
+            {
+                if (!expectVeto)
+                    fail("Unexpected PropertyVetoException: " + i);
+            }
+            else
+            {
+                if (expectVeto)
+                    fail("Did not receive expected PropertVetoException: " + i);
+
+                expected = i;
+            }
+
+            //
+            // Read back the property and see if it was successfully changed or vetoed
+            if (eventBean.getConstrainedInt() != expected)
+                fail("Did not get expected value: " + expected + " for " + i);
+        }
+
+        // Now validate the received properties, there should be one per vetoed property,
+        // two per allowed change
+        int i = 1;
+        expected = 0;
+        boolean expectVeto = false;
+        Iterator<PropertyChangeEvent> changeIter = ctl.getEvents().iterator();
+        Iterator<PropertyChangeEvent> vetoIter = vtl.getEvents().iterator();
+        while(vetoIter.hasNext())
+        {
+            PropertyChangeEvent vce = vetoIter.next();
+
+            expectVeto = (i & 1) == 0;
+
+            if (vce.getSource() != eventBean)
+                fail("Invalid source value in PropertyChangeEvent");
+
+            if (!vce.getPropertyName().equals("constrainedInt"))
+                fail("Invalid property name: " + vce.getPropertyName());
+
+            if (!vce.getOldValue().equals(new Integer(expected)))
+                fail("Unexpected old value: " + vce.getOldValue() + ", expected: " + expected);
+
+            if (!vce.getNewValue().equals(new Integer(i)))
+                fail("Unexpected new value: " + vce.getNewValue() + ", expected: " + i);
+
+            if (expectVeto)
+            {
+                // If a veto occurred, then there should be a 2nd vetoable change event that
+                // goes from the vetoed value back to the last valid value
+                if (!vetoIter.hasNext())
+                    fail("Did not find expected veto revert event");
+                
+                //
+                // Pull the next event, which should revert from the attempted change back
+                // to the last accepted value
+                //
+                vce = vetoIter.next();
+                if (vce.getSource() != eventBean)
+                    fail("Invalid source value in PropertyChangeEvent");
+
+                if (!vce.getPropertyName().equals("constrainedInt"))
+                    fail("Invalid property name: " + vce.getPropertyName());
+
+                if (!vce.getOldValue().equals(new Integer(i)))
+                    fail("Unexpected old value: " + vce.getOldValue() + ", expected: " + i);
+
+                if (!vce.getNewValue().equals(new Integer(expected)))
+                    fail("Unexpected new value: " + vce.getNewValue() + ", expected: " + expected);
+            }
+            else
+            {
+                // Expected to succeed so look for the corresponding PropertyChange
+                if (!changeIter.hasNext())
+                    fail("Missing PropertyChange event");
+
+                PropertyChangeEvent pce = changeIter.next();
+                if (pce.getSource() != eventBean)
+                    fail("Invalid source value in PropertyChangeEvent");
+
+                if (!pce.getPropertyName().equals("constrainedInt"))
+                    fail("Invalid property name: " + pce.getPropertyName());
+
+                if (!pce.getOldValue().equals(new Integer(expected)))
+                    fail("Unexpected old value: " + pce.getOldValue() + ", expected: " + expected);
+
+                if (!pce.getNewValue().equals(new Integer(i)))
+                    fail("Unexpected new value: " + pce.getNewValue() + ", expected: " + i);
+
+                expected = i;
+            }
+
+            i++;
+        }
+        if (expected != 99)
+            fail("Received less events than expected: " + expected);
+
+        // Reset the event queue
+        vtl.initEvents();
+        ctl.initEvents();
+
+        // Change an unbound property and verify that no property change event was delivered
+        eventBean.setBasicInt(0);
+        if (vtl.getEvents().size() != 0 || ctl.getEvents().size() != 0)
+            fail("Unexpected event delivered on unbound property change");
+
+        // Remove the veto event listener but not the change listener, change a constrained 
+        // property, and verify no veto event is delivered but a change event is delivered
+        eventBean.removeVetoableChangeListener(vtl);
+        eventBean.setConstrainedInt(1);
+        if (vtl.getEvents().size() != 0)
+            fail("Unexpected event delivered after listener removed");
+        if (ctl.getEvents().size() != 1)
+            fail("Change event not delivered after listener removed");
+    }
+}