You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by cs...@apache.org on 2006/04/26 17:22:52 UTC

svn commit: r397220 - in /beehive/trunk/controls: src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ test/src/junit-tests/org/apache/beehive/controls/test/junit/

Author: cschoett
Date: Wed Apr 26 08:22:50 2006
New Revision: 397220

URL: http://svn.apache.org/viewcvs?rev=397220&view=rev
Log:
Fixed a bug in handling BeanContext children which implement the BeanContextProxy interface. Only the Proxy was being added as a child instead of both the proxy and BCC it references.
Updated unit tests for this change.

Modified:
    beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextServicesSupport.java
    beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextSupport.java
    beehive/trunk/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java

Modified: beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextServicesSupport.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextServicesSupport.java?rev=397220&r1=397219&r2=397220&view=diff
==============================================================================
--- beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextServicesSupport.java (original)
+++ beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextServicesSupport.java Wed Apr 26 08:22:50 2006
@@ -258,6 +258,9 @@
         ServiceProvider sp = _serviceProviders.get(serviceClass);
         sp.removeChildReference(requestor);
 
+        // if this is a delegated service, delegate the release request
+        // delegated services are removed from the _serviceProviders table
+        // as soon as their reference count drops to zero
         if (sp.isDelegated()) {
             BeanContextServices bcs = (BeanContextServices) getBeanContext();
             bcs.releaseService(this, requestor, service);
@@ -386,8 +389,8 @@
     /**
      * Initialize data structures.
      */
-    protected void init() {
-        super.init();
+    protected void initialize() {
+        super.initialize();
         _serviceProviders = Collections.synchronizedMap(new HashMap<Class, ServiceProvider>());
         _bcsListeners = Collections.synchronizedList(new ArrayList<BeanContextServicesListener>());
     }

Modified: beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextSupport.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextSupport.java?rev=397220&r1=397219&r2=397220&view=diff
==============================================================================
--- beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextSupport.java (original)
+++ beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/webcontext/ControlBeanContextSupport.java Wed Apr 26 08:22:50 2006
@@ -25,10 +25,10 @@
 import java.beans.VetoableChangeListener;
 import java.beans.Visibility;
 import java.beans.beancontext.BeanContext;
-import java.beans.beancontext.BeanContextChild;
 import java.beans.beancontext.BeanContextMembershipEvent;
 import java.beans.beancontext.BeanContextMembershipListener;
 import java.beans.beancontext.BeanContextProxy;
+import java.beans.beancontext.BeanContextChild;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectOutputStream;
@@ -37,9 +37,10 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
 
 /**
  * BeanContext implementation for Beehive Controls.
@@ -49,8 +50,8 @@
 
     private static final long serialVersionUID = 1L;
 
-    private transient List _children;
-    private transient HashSet<BeanContextMembershipListener> _bcMembershipListeners;
+    private transient Map<Object, BCChild> _children;
+    private transient List<BeanContextMembershipListener> _bcMembershipListeners;
 
     private boolean _designTime = false;
     private boolean _mayUseGui = false;
@@ -60,7 +61,7 @@
      */
     public ControlBeanContextSupport() {
         super();
-        init();
+        initialize();
     }
 
     /**
@@ -68,9 +69,9 @@
      *
      * @param bcc
      */
-    public ControlBeanContextSupport(BeanContextChild bcc) {
+    public ControlBeanContextSupport(java.beans.beancontext.BeanContextChild bcc) {
         super(bcc);
-        init();
+        initialize();
     }
 
     /**
@@ -88,7 +89,7 @@
      *                                by the beanName parameter is not found
      */
     public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException {
-        BeanContextChild bcc = getBCCDelegate();
+        java.beans.beancontext.BeanContextChild bcc = getBCCDelegate();
         return Beans.instantiate(bcc.getClass().getClassLoader(), beanName, (BeanContext) bcc);
     }
 
@@ -105,7 +106,7 @@
      *         be found.
      * @throws IllegalArgumentException if the resource is not valid
      */
-    public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException {
+    public InputStream getResourceAsStream(String name, java.beans.beancontext.BeanContextChild bcc) throws IllegalArgumentException {
 
         // bcc must be a child of this context
         if (!contains(bcc)) {
@@ -132,7 +133,7 @@
      *         resource for the specified child
      * @throws IllegalArgumentException if the resource is not valid
      */
-    public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException {
+    public URL getResource(String name, java.beans.beancontext.BeanContextChild bcc) throws IllegalArgumentException {
 
         // bcc must be a child of this context
         if (!contains(bcc)) {
@@ -206,26 +207,21 @@
      *                              collection does not support null elements (optional).
      */
     public boolean contains(Object o) {
-        return _children.contains(o);
+        return _children.containsKey(o);
     }
 
     /**
-     * Returns an iterator over the elements in this collection.  There are no
-     * guarantees concerning the order in which the elements are returned
-     * (unless this collection is an instance of some class that provides a
-     * guarantee).
+     * Returns an iterator over the elements in this collection.  The
+     * iterator's collection is non-modifiable.
      *
      * @return an <tt>Iterator</tt> over the elements in this collection
      */
     public Iterator iterator() {
-        return Collections.unmodifiableList(_children).iterator();
+        return Collections.unmodifiableSet(_children.keySet()).iterator();
     }
 
     /**
-     * Returns an array containing all of the elements in this collection.  If
-     * the collection makes any guarantees as to what order its elements are
-     * returned by its iterator, this method must return the elements in the
-     * same order.<p>
+     * Returns an array containing all of the elements in this collection.
      * <p/>
      * The returned array will be "safe" in that no references to it are
      * maintained by this collection.  (In other words, this method must
@@ -238,7 +234,7 @@
      * @return an array containing all of the elements in this collection
      */
     public Object[] toArray() {
-        return _children.toArray();
+        return _children.keySet().toArray();
     }
 
     /**
@@ -277,14 +273,20 @@
         if (contains(o)) return false;
 
         // todo: for multithreaded usage this block needs to be synchronized
-        // spec says if the object being added implements BeanContextChild or BeanContextProxy
+        // spec: if the object being added implements BeanContextChild or BeanContextProxy
         // need to set the bean context of the object to this bean context.
-        BeanContextChild bcc = null;
+        java.beans.beancontext.BeanContextChild bcc = null;
+        BeanContextProxy bcp = null;
+
         if (o instanceof BeanContextProxy) {
-            bcc = ((BeanContextProxy) o).getBeanContextProxy();
+            if (o instanceof BeanContext) {
+                throw new IllegalArgumentException("May not implement both BeanContextProxy and BeanContext!!");
+            }
+            bcp = (BeanContextProxy)o;
+            bcc = bcp.getBeanContextProxy();
         }
-        else if (o instanceof BeanContextChild) {
-            bcc = (BeanContextChild) o;
+        else if (o instanceof java.beans.beancontext.BeanContextChild) {
+            bcc = (java.beans.beancontext.BeanContextChild) o;
         }
 
         if (bcc != null) {
@@ -312,7 +314,12 @@
             addBeanContextMembershipListener((BeanContextMembershipListener) o);
         }
 
-        _children.add(o);
+        if (bcp == null) {
+            _children.put(o, new BCChild(o));
+        } else {
+            _children.put(o, new BCChild(bcp, bcc, true));
+            _children.put(bcc, new BCChild(bcp, bcc, false));
+        }
 
         BeanContextMembershipEvent bcme = new BeanContextMembershipEvent(this, new Object[]{o});
         fireMembershipEvent(bcme, true);
@@ -344,27 +351,9 @@
     }
 
     /**
-     * Adds all of the elements in the specified collection to this collection
-     * (optional operation).  The behavior of this operation is undefined if
-     * the specified collection is modified while the operation is in progress.
-     * (This implies that the behavior of this call is undefined if the
-     * specified collection is this collection, and this collection is
-     * nonempty.)
+     * Not supported.
      *
-     * @param c elements to be inserted into this collection.
-     * @return <tt>true</tt> if this collection changed as a result of the
-     *         call
-     * @throws UnsupportedOperationException if this collection does not
-     *                                       support the <tt>addAll</tt> method.
-     * @throws ClassCastException            if the class of an element of the specified
-     *                                       collection prevents it from being added to this collection.
-     * @throws NullPointerException          if the specified collection contains one
-     *                                       or more null elements and this collection does not support null
-     *                                       elements, or if the specified collection is <tt>null</tt>.
-     * @throws IllegalArgumentException      some aspect of an element of the
-     *                                       specified collection prevents it from being added to this
-     *                                       collection.
-     * @see #add(Object)
+     * @throws UnsupportedOperationException
      */
     public boolean addAll(Collection c) {
         // NOOP : Not Supported
@@ -372,12 +361,9 @@
     }
 
     /**
-     * Removes all of the elements from this collection (optional operation).
-     * This collection will be empty after this method returns unless it
-     * throws an exception.
+     * Not supported.
      *
-     * @throws UnsupportedOperationException if the <tt>clear</tt> method is
-     *                                       not supported by this collection.
+     * @throws UnsupportedOperationException
      */
     public void clear() {
         // NOOP: Not supported
@@ -385,26 +371,9 @@
     }
 
     /**
-     * Retains only the elements in this collection that are contained in the
-     * specified collection (optional operation).  In other words, removes from
-     * this collection all of its elements that are not contained in the
-     * specified collection.
+     * Not supported.
      *
-     * @param c elements to be retained in this collection.
-     * @return <tt>true</tt> if this collection changed as a result of the
-     *         call
-     * @throws UnsupportedOperationException if the <tt>retainAll</tt> method
-     *                                       is not supported by this Collection.
-     * @throws ClassCastException            if the types of one or more elements
-     *                                       in this collection are incompatible with the specified
-     *                                       collection (optional).
-     * @throws NullPointerException          if this collection contains one or more
-     *                                       null elements and the specified collection does not support null
-     *                                       elements (optional).
-     * @throws NullPointerException          if the specified collection is
-     *                                       <tt>null</tt>.
-     * @see #remove(Object)
-     * @see #contains(Object)
+     * @throws UnsupportedOperationException
      */
     public boolean retainAll(Collection c) {
         // NOOP: Not supported
@@ -412,26 +381,9 @@
     }
 
     /**
-     * Removes all this collection's elements that are also contained in the
-     * specified collection (optional operation).  After this call returns,
-     * this collection will contain no elements in common with the specified
-     * collection.
+     * Not supported.
      *
-     * @param c elements to be removed from this collection.
-     * @return <tt>true</tt> if this collection changed as a result of the
-     *         call
-     * @throws UnsupportedOperationException if the <tt>removeAll</tt> method
-     *                                       is not supported by this collection.
-     * @throws ClassCastException            if the types of one or more elements
-     *                                       in this collection are incompatible with the specified
-     *                                       collection (optional).
-     * @throws NullPointerException          if this collection contains one or more
-     *                                       null elements and the specified collection does not support
-     *                                       null elements (optional).
-     * @throws NullPointerException          if the specified collection is
-     *                                       <tt>null</tt>.
-     * @see #remove(Object)
-     * @see #contains(Object)
+     * @throws UnsupportedOperationException
      */
     public boolean removeAll(Collection c) {
         throw new UnsupportedOperationException();
@@ -455,7 +407,7 @@
      * @see #contains(Object)
      */
     public boolean containsAll(Collection c) {
-        return _children.containsAll(c);
+        return _children.keySet().containsAll(c);
     }
 
     /**
@@ -502,7 +454,7 @@
      * @throws NullPointerException if the specified array is <tt>null</tt>.
      */
     public Object[] toArray(Object[] a) {
-        return _children.toArray(a);
+        return _children.keySet().toArray(a);
     }
 
     /**
@@ -537,7 +489,6 @@
      *
      * @return the current "value" of the "designTime" property.
      */
-
     public boolean isDesignTime() {
         return _designTime;
     }
@@ -549,13 +500,13 @@
      *         order to get its work done.
      */
     public boolean needsGui() {
-        BeanContextChild bcc = getBCCDelegate();
+        java.beans.beancontext.BeanContextChild bcc = getBCCDelegate();
         if (bcc != this && bcc instanceof Visibility) {
             return ((Visibility) bcc).needsGui();
         }
 
         // check children
-        for (Object o : _children) {
+        for (Object o : _children.keySet()) {
             if (o instanceof Visibility) {
                 if (((Visibility) o).needsGui()) {
                     return true;
@@ -573,7 +524,7 @@
 
         _mayUseGui = false;
 
-        for (Object o : _children) {
+        for (Object o : _children.keySet()) {
             if (o instanceof Visibility) {
                 ((Visibility) o).dontUseGui();
             }
@@ -588,7 +539,7 @@
 
         _mayUseGui = true;
 
-        for (Object o : _children) {
+        for (Object o : _children.keySet()) {
             if (o instanceof Visibility) {
                 ((Visibility) o).okToUseGui();
             }
@@ -646,9 +597,9 @@
     /**
      * Init this classes data structures.
      */
-    protected void init() {
-        _bcMembershipListeners = new HashSet<BeanContextMembershipListener>();
-        _children = Collections.synchronizedList(new ArrayList<Object>());
+    protected void initialize() {
+        _bcMembershipListeners = new ArrayList<BeanContextMembershipListener>();
+        _children = Collections.synchronizedMap(new HashMap<Object, BCChild>());
     }
 
     /**
@@ -682,12 +633,14 @@
         if (!contains(o)) return false;
 
         // todo: for multithreaded usage this block needs to be synchronized
-        BeanContextChild bcc = null;
+        java.beans.beancontext.BeanContextChild bcc = null;
+        BeanContextProxy bcp = null;
         if (o instanceof BeanContextProxy) {
-            bcc = ((BeanContextProxy) o).getBeanContextProxy();
+            bcp = (BeanContextProxy)o;
+            bcc = bcp.getBeanContextProxy();
         }
         else if (o instanceof BeanContextChild) {
-            bcc = (BeanContextChild) o;
+            bcc = (java.beans.beancontext.BeanContextChild) o;
         }
 
         if (bcc != null) {
@@ -721,7 +674,18 @@
             removeBeanContextMembershipListener((BeanContextMembershipListener) o);
         }
 
-        _children.remove(o);
+        if (bcp != null) {
+            // need to remove the peer as well
+            BCChild c = _children.get(bcp);
+            _children.remove(c.getChild());
+            _children.remove(o);
+        } else {
+            BCChild c = _children.get(o);
+            if (c.hasProxy()) {
+                _children.remove(c.getProxy());
+            }
+            _children.remove(o);
+        }
 
         BeanContextMembershipEvent bcme = new BeanContextMembershipEvent(this, new Object[]{o});
         fireMembershipEvent(bcme, false);
@@ -740,22 +704,24 @@
         out.defaultWriteObject();
 
         // spec: only write children if not using a delegate
-        int serializable = 0;
-        for (Object child : _children) {
-            if (child instanceof Serializable) serializable++;
+        ArrayList<Object> serChildren = new ArrayList<Object>();
+        for (Object child : _children.keySet()) {
+            BCChild bcc = _children.get(child);
+            // only write children which do not have a proxy / or directly implement the BeanContextProxy interface
+            if ((!bcc.hasProxy() || bcc.hasProxy() && bcc.isProxy()) && bcc.isSerializable()) {
+                serChildren.add(child);
+            }
         }
 
-        out.writeInt(serializable);
+        out.writeInt(serChildren.size());
         if (this.equals(getBCCDelegate())) {
-            for (Object child : _children) {
-                if (child instanceof Serializable) {
-                    out.writeObject(child);
-                }
+            for (Object child : serChildren) {
+                out.writeObject(child);
             }
         }
 
         // write event handlers
-        serializable = 0;
+        int serializable = 0;
         for (BeanContextMembershipListener listener : _bcMembershipListeners) {
             if (listener instanceof Serializable) serializable++;
         }
@@ -780,7 +746,7 @@
 
         // todo: for multithreaded usage this block needs to be synchronized
         in.defaultReadObject();
-        init();
+        initialize();
 
         int childCount = in.readInt();
         for (int i = 0; i < childCount; i++) {
@@ -797,5 +763,86 @@
             addBeanContextMembershipListener((BeanContextMembershipListener) in.readObject());
         }
         // end synchronized block
+    }
+
+    /**
+     * A child of this BeanContext.  This class is used to manage the relationship
+     * between a BeanContextProxy and its BeanContextChild.  When a BeanContextProxy
+     * is added or removed from this context the BeanContextChild it references must
+     * also be added or removed.  This requires that both the BeanContextChild and
+     * BeanContextProxy are added/removed to the list of children.  This class
+     * is used to map from the proxy -> child and child -> proxy.
+     *
+     * The _child field is always guarenteed to be non-null, the proxy field may
+     * be null if this child does not have a proxy.
+     */
+    private final static class BCChild {
+
+        private Object _child;
+        private BeanContextProxy _proxy;
+        private boolean _isProxy;
+
+        /**
+         * Construct a new BCChild for a child which is not related to a BeanContextProxy.
+         * @param child child to add -- must not be an instance of BeanContextProxy.
+         */
+        protected BCChild(Object child) {
+            assert child != null;
+            assert !(child instanceof BeanContextProxy);
+
+            _child = child;
+            _proxy = null;
+            _isProxy = false;
+        }
+
+        /**
+         * Construct a new BCChild for a proxy -> child relationship.
+         * @param proxy BeanContextProxy
+         * @param child BeanContextChild
+         * @param isProxy true if this will be entered into the child map keyed on the proxy.
+         */
+        protected BCChild(BeanContextProxy proxy, BeanContextChild child, boolean isProxy) {
+            assert child != null;
+            assert proxy != null;
+
+            _child = child;
+            _proxy = proxy;
+            _isProxy = isProxy;
+        }
+
+        /**
+         * Get the proxy.
+         */
+        protected BeanContextProxy getProxy() {
+            return _proxy;
+        }
+
+        /**
+         * Get the child.
+         */
+        protected Object getChild() {
+            return _child;
+        }
+
+        /**
+         * True if a proxy was set for this child.
+         */
+        protected boolean hasProxy() {
+            return _proxy != null;
+        }
+
+        /**
+         * True if this child was keyed by its proxy in the child map.
+         */
+        protected boolean isProxy() {
+            return _isProxy;
+        }
+
+        /**
+         * True if this BCChild is serializable.
+         */
+        protected boolean isSerializable() {
+            return (_proxy != null) ? _proxy instanceof Serializable && _child instanceof Serializable : _child instanceof Serializable;
+        }
     }
 }

Modified: beehive/trunk/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java?rev=397220&r1=397219&r2=397220&view=diff
==============================================================================
--- beehive/trunk/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java (original)
+++ beehive/trunk/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java Wed Apr 26 08:22:50 2006
@@ -177,24 +177,20 @@
 
     /**
      * Test interator() collection api. Iterator returned should not
-     * allow for removal of items.
+     * allow for removal of items. NOTE: ControlBeanContextSupport
+     * uses a Map to store its children so the iteration order
+     * is not predictable.
      */
     public void testIterator() {
 
         ControlBeanContextSupport cbcs = getContext();
         ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport();
-        ControlBeanContextChildSupport child2 = new ControlBeanContextChildSupport();
-
         assertTrue(cbcs.add(child1));
-        assertTrue(cbcs.add(child2));
 
         Iterator i = cbcs.iterator();
         assertTrue(i.hasNext());
         assertEquals(child1, i.next());
 
-        assertTrue(i.hasNext());
-        assertEquals(child2, i.next());
-
         try {
             i.remove();
         }
@@ -305,10 +301,10 @@
         assertNull(pce[0].getOldValue());
         assertEquals(cbcs, pce[0].getNewValue());
 
-        // that the child was added to the collection
+        // test that the proxy as well as the bcc it references were added to the bean context
+        // as children -- may seem a bit odd but the spec says it should work this way!
         Object[] children = cbcs.toArray();
-        assertEquals(1, children.length);
-        assertEquals(proxy, children[0]);
+        assertEquals(2, children.length);
     }
 
     /**
@@ -433,7 +429,7 @@
         assertNull(pce[0].getNewValue());
         assertEquals(cbcs, pce[0].getOldValue());
 
-        // that the child was added to the collection
+        // that the child was removed from the collection
         Object[] children = cbcs.toArray();
         assertEquals(0, children.length);
     }