Author: kylem
Date: Fri Oct  8 12:23:17 2004
New Revision: 54105

Added:
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplInitializer.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.vm
Removed:
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlInitializer.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlInitializer.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlInitializer.vm
Modified:
   
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/bean/ControlBeanContext.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlImpl.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlImplementation.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlInterface.java
   incubator/beehive/trunk/controls/test/build.xml
   
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.jcs
   
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/context/BaseContextBeanDriver.java
   
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/context/ContextTest.java
Log:
Modified ControlBean serialization so all references to contextual services 
will be nulled
prior to serialization.  If the bean instance is deserialized, contextual 
services refs are
lazily reconnected upon the first invocation on the bean.   The implication, 
though, is that
all contextual services should be stateless, at least w.r.t. serialization 
boundaries of the
container controls are executing in.

Added a junit test case to validate that behavior, that will inspect service 
references in 
writeObject (to ensure they are null) and exercises contextual services after 
deserialization.

Also did some minor cleanup on how control impl initialization is done so it 
could be
leverage for the service re-init above.  Pushed invocation of nested control 
ref initializer
down into the generated impl initializer, instead of doing it generically using 
reflection
in the ControlBean base class.



Modified: 
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/bean/ControlBean.java
      (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java
      Fri Oct  8 12:23:17 2004
@@ -24,10 +24,12 @@
 import java.beans.beancontext.BeanContextServiceRevokedListener;
 import java.beans.beancontext.BeanContextServiceRevokedEvent;
 import java.beans.beancontext.BeanContextSupport;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Method;
 import java.lang.reflect.Field;
-import java.lang.annotation.Annotation;
 import java.util.*;
 
 import org.apache.beehive.controls.api.ControlException;
@@ -278,6 +280,29 @@
     }
 
     /**
+     * Obtains an instance of the appropriate ImplInitializer class
+     */
+    public ImplInitializer getImplInitializer()
+    {
+        if (_implInitializer == null)
+        {
+            try
+            {
+                ControlBeanContext context = getBeanContextProxy();
+                Class implClass = context.getControlBinding(_controlClass);
+                Class initClass = implClass.getClassLoader().loadClass(
+                                        implClass.getName() + "Initializer");
+                _implInitializer = (ImplInitializer)initClass.newInstance();
+            }
+            catch (Exception e)
+            {
+                throw new ControlException("Control initialization failure", 
e);
+            }
+        }
+        return _implInitializer;
+    }
+
+    /**
      * Returns the target control instance associated with this ControlBean, 
performing lazy
      * instantiation and initialization of the instance.
      */
@@ -301,27 +326,8 @@
 
                 try
                 {
-                    if ( isControlClient( implClass ) )
-                    {
-                        // TODO: localize computation of initializer classname
-                        Class clientInitClass = 
implClass.getClassLoader().loadClass(
-                                                    implClass.getName() + 
"ClientInitializer" );
-
-                        Method clientInitMethod =
-                            clientInitClass.getMethod( "initialize",
-                                                       
org.apache.beehive.controls.api.context.ControlBeanContext.class,
-                                                       implClass );
-                        if ( clientInitMethod == null )
-                           throw new Exception( "Control client init class " + 
clientInitClass +
-                                                " missing initialize() method" 
);
-
-                        clientInitMethod.invoke( null, 
this.getControlBeanContext(), _control );
-                    }
-
-                    Class initClass = implClass.getClassLoader().loadClass(
-                                            implClass.getName() + 
"Initializer");
-                    ControlInitializer initializer = 
(ControlInitializer)initClass.newInstance();
-                    initializer.initialize(this, _control);
+                    getImplInitializer().initialize(this, _control);
+                    _hasServices = true;
                 }
                 catch (Exception e)
                 {
@@ -341,6 +347,17 @@
                 throw new ControlException("Unable to create control 
instance", e);
             }
         }
+
+        //
+        // If the implementation instance does not currently have contextual 
services, they
+        // are lazily restored here.
+        //
+        if (!_hasServices)
+        {
+            getImplInitializer().initServices(this, _control);
+            _hasServices = true;
+        }
+
         return _control;
     }
 
@@ -358,11 +375,11 @@
         if (_invokeLock != null)
             _invokeLock.lock();
 
-        if (_invokeListeners.size() > 0)
+        Vector<InvokeListener> invokeListeners = getInvokeListeners();
+        if (invokeListeners.size() > 0)
         {
-            Iterator iter = _invokeListeners.iterator();
-            while (iter.hasNext())
-                ((InvokeListener)iter.next()).preInvoke(m, args);
+            for (InvokeListener listener : invokeListeners)
+                listener.preInvoke(m, args);
         }
     }
 
@@ -375,11 +392,11 @@
     {
         try
         {
-            if (_invokeListeners.size() > 0)
+            Vector<InvokeListener> invokeListeners = getInvokeListeners();
+            if (invokeListeners.size() > 0)
             {
-                Iterator iter = _invokeListeners.iterator();
-                while (iter.hasNext())
-                    ((InvokeListener)iter.next()).postInvoke(retval, t);
+                for (InvokeListener listener : invokeListeners)
+                    listener.postInvoke(retval, t);
             }
         }
         finally
@@ -397,7 +414,7 @@
      */
     protected void setEventNotifier(Class eventSet, EventNotifier notifier)
     {
-        _callbackNotifiers.put(eventSet,notifier);
+        _notifierMap.put(eventSet,notifier);
 
         //
         // Register this notifier for all EventSet interfaces up the interface 
inheritance
@@ -409,7 +426,7 @@
         while (i.hasNext())
         {
             Class superEventSet = i.next();
-            _callbackNotifiers.put(superEventSet,notifier);
+            _notifierMap.put(superEventSet,notifier);
         }
     }
 
@@ -443,7 +460,14 @@
      */
     protected EventNotifier getEventNotifier(Class eventSet)
     {
-        return _callbackNotifiers.get(eventSet);
+        return _notifierMap.get(eventSet);
+    }
+
+    private Vector<InvokeListener> getInvokeListeners()
+    {
+        if (_invokeListeners == null)
+            _invokeListeners = new Vector<InvokeListener>();
+        return _invokeListeners;
     }
 
     /**
@@ -451,7 +475,7 @@
      */
     public void addInvokeListener(InvokeListener invokeListener)
     {
-        _invokeListeners.addElement(invokeListener);
+        getInvokeListeners().addElement(invokeListener);
     }
 
     /**
@@ -459,7 +483,7 @@
      */
     public void removeInvokeListener(InvokeListener invokeListener)
     {
-        _invokeListeners.removeElement(invokeListener);
+        getInvokeListeners().removeElement(invokeListener);
     }
 
     /**
@@ -636,25 +660,22 @@
     }
 
     /**
-     * Determines if the control impl class uses controls (is a control client)
+     * Implementation of the Java serialization writeObject method
      */
-    protected boolean isControlClient( Class implClass )
+    private synchronized void writeObject(ObjectOutputStream oos) 
+                              throws IOException, ClassNotFoundException 
     {
-        // Examine all fields for @Control annotation.
-        // Can't use Class.getFields() since that only returns public fields
-        while ( implClass != null )
+        //
+        // Reset any contextual service references held by the implementation 
prior to
+        // serialization.  These will be lazily restored (if necessary) by 
ensureControl.
+        //
+        if (_control != null)
         {
-            Field [] fields = implClass.getDeclaredFields();
-            for ( Field f : fields )
-            {
-                if ( f.getAnnotation( 
org.apache.beehive.controls.api.bean.Control.class ) != null )
-                    return true;
-            }
-
-            implClass = implClass.getSuperclass();
+            getImplInitializer().resetServices(this, _control);    
+            _hasServices = false;
         }
 
-        return false;
+        oos.defaultWriteObject();
     }
 
     /**
@@ -683,20 +704,20 @@
     private ControlBeanContext _cbc;
 
     /**
-     * This field manages the register listener list(s) associated with event 
set interfaces
-     * for the ControlBean.
+     *  Contains the per-instance properties set for this ControlBean.
      */
-    private HashMap<Class, EventNotifier> _callbackNotifiers = new 
HashMap<Class,EventNotifier>();
+    private PropertyMap _properties;
 
     /**
-     * Maintains the list of callback event listeners (if any) for this 
ControlBean.
+     * This field manages the register listener list(s) associated with event 
set interfaces
+     * for the ControlBean.
      */
-    private Vector _invokeListeners = new Vector();
+    private HashMap<Class, EventNotifier> _notifierMap = new 
HashMap<Class,EventNotifier>();
 
     /**
-     *  Contains the per-instance properties set for this ControlBean.
+     * Maintains the list of callback event listeners (if any) for this 
ControlBean.
      */
-    private PropertyMap _properties;
+    transient private Vector<InvokeListener> _invokeListeners;
 
     /**
      * Used to guarantee single threaded invocation when required.  If the
@@ -704,4 +725,16 @@
      * is threadsafe, then the value will be null.
      */
     transient private Mutex _invokeLock;
+
+    /**
+     * An ImplInitializer instances used to initialize/reset the state of the 
associated
+     * implementation instance.
+     */
+    transient private ImplInitializer _implInitializer;
+
+    /**
+     * Indicates whether the contextual services associated with the bean have 
been
+     * fully initialized.
+     */
+    transient private boolean _hasServices = false;
 }

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
       (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
       Fri Oct  8 12:23:17 2004
@@ -736,5 +736,5 @@
     /**
      * Maintains the list of lifecycle event listeners (if any) for this 
context.
      */
-    private Vector<LifeCycle> _lifeCycleListeners;
+    transient private Vector<LifeCycle> _lifeCycleListeners;
 }

Added: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplInitializer.java
==============================================================================
--- (empty file)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplInitializer.java
  Fri Oct  8 12:23:17 2004
@@ -0,0 +1,77 @@
+package org.apache.beehive.controls.runtime.bean;
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+import java.lang.reflect.AnnotatedElement;
+import org.apache.beehive.controls.api.properties.PropertyMap;
+
+/**
+ * The ImplInitializer class is an abstract base class that all generated 
Control
+ * initalization classes will extend.  It provides common utilities and 
supporting code
+ * for initialization, and has a shared package relationship with the base 
ControlBean
+ * class providing access to internals not available in a more general context.
+ */
+abstract public class ImplInitializer
+{
+    /**
+     * Initializes a new ControlImplementation instance associated with the 
specified bean.
+     */
+    public void initialize(ControlBean bean, Object target)
+    {
+        initServices(bean, target);
+        initControls(bean, target);
+        initEventProxies(bean, target);
+    }
+
+    /**
+     * Initializes all contextual services required by the target 
implementation instance.
+     * The default initializer implementation is a noop, but will be 
overridden by
+     * generated subclasses that contain contextual services.
+     */
+    public void initServices(ControlBean bean, Object target) { };
+
+    /**
+     * Resets all contextual services on the target implementation instance to 
null.
+     * The default initializer implementation is a noop, but will be 
overridden by
+     * generated subclasses that contain contextual services.
+     */
+    public void resetServices(ControlBean bean, Object target) { };
+
+    /**
+     * Initializes all nested controls required by the target implementation 
instance.
+     * The default initializer implementation is a noop, but will be 
overridden by
+     * generated subclasses that contain nested controls
+     */
+    public void initControls(ControlBean bean, Object target) { };
+
+    /**
+     * Initializes all event proxies required by the target implementation 
instance.
+     * The default initializer implementation is a noop, but will be 
overridden by
+     * generated subclasses that contain event proxies
+     */
+    public void initEventProxies(ControlBean bean, Object target) { };
+
+
+    /**
+     * Returns the ControlBean event notifer for the specified eventSet
+     */
+    public EventNotifier getEventNotifier(ControlBean bean, Class eventSet)
+    {
+        return bean.getEventNotifier(eventSet);
+    }
+}

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlImpl.java
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlImpl.java
 (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlImpl.java
 Fri Oct  8 12:23:17 2004
@@ -40,13 +40,13 @@
         _superClass = initSuperClass();
         _contexts = initContexts();
         _clients = initClients();
-        _ignoredEventFields = initIgnoredEventFields();
+        _controls = initControls();
         initEventAdaptors();
 
         //
         // Construct a new initializer class from this implementation class
         //
-        _init = new ControlInitializer(this);
+        _init = new ImplInitializer(this);
     }
 
     /**
@@ -71,13 +71,12 @@
     abstract protected ArrayList<ClientField> initClients();
 
     /**
-     * Initializes the list of fields for which event handlers should be 
ignored
-     * for this ControlImpl.
-     *
-     * This allows multiple annotation processors to process event handlers 
without
-     * spurious errors.
+     * Initializes the list of control fields for this ControlImpl.  While 
nested
+     * control references are processed by a different processor, we identify
+     * them so they can be ignored.  This allows multiple annotation 
processors to process 
+     * event handlers without spurious errors.
      */
-    abstract protected ArrayList<EventField> initIgnoredEventFields();
+    abstract protected ArrayList<ControlField> initControls();
 
     /**
      * Returns the super interface for this interface
@@ -90,17 +89,22 @@
     public ArrayList<ContextField> getContexts() { return _contexts; }
 
     /**
-     * Returns true if the implemenation class contains any nested controls
+     * Returns true if the implemenation class contains any nested services
      */
     public boolean hasContexts() { return _contexts.size() != 0; }
 
     /**
+     * Returns true if the implemenation class contains any nested controls
+     */
+    public boolean hasControls() { return _controls.size() != 0; }
+
+    /**
      * Returns the list of ClientFields declared directly by this ControlImpl
      */
     public ArrayList<ClientField> getClients() { return _clients; }
 
     /**
-     * Returns true if the implemenation class contains any nested controls
+     * Returns true if the implemenation class contains any nested event 
proxies
      */
     public boolean hasClients() { return _clients.size() != 0; }
 
@@ -110,14 +114,6 @@
     abstract protected void initEventAdaptors(); 
 
     /**
-     * Returns true if the control implementation needs field initialization 
support
-     */
-    public boolean needsFieldInit()
-    {
-        return hasContexts() || hasClients();
-    }
-
-    /**
      * Returns the field with the specified name
      */
     public GenField getField(String name)
@@ -132,11 +128,11 @@
         return null;
     }
 
-    public EventField getIgnoredEventField(String name)
+    public EventField getControlField(String name)
     {
-        for (EventField eventField : _ignoredEventFields)
-            if (eventField.getName().equals(name))
-                return eventField;
+        for (ControlField controlField : _controls)
+            if (controlField.getName().equals(name))
+                return controlField;
         
         return null;
     }
@@ -151,7 +147,7 @@
     }
 
     /**
-     * Returns the information necessary to generate a ControlInitializer from 
this
+     * Returns the information necessary to generate a ImplInitializer from 
this
      * ControlImplementation.
      */
     public List<GeneratorOutput> getCheckOutput(Filer filer) throws IOException
@@ -162,7 +158,7 @@
 
         Writer writer = new 
IndentingWriter(filer.createSourceFile(_init.getClassName()));
         GeneratorOutput genOut = 
-            new 
GeneratorOutput(writer,"org/apache/beehive/controls/runtime/generator/ControlInitializer.vm",
+            new 
GeneratorOutput(writer,"org/apache/beehive/controls/runtime/generator/ImplInitializer.vm",
                                 map);
         ArrayList<GeneratorOutput> genList = new ArrayList<GeneratorOutput>(1);
         genList.add(genOut);
@@ -172,6 +168,6 @@
     ControlImpl _superClass;
     ArrayList<ContextField> _contexts;
     ArrayList<ClientField> _clients;
-    ArrayList<EventField> _ignoredEventFields;
-    ControlInitializer _init;
+    ArrayList<ControlField> _controls;
+    ImplInitializer _init;
 }

Added: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.java
==============================================================================
--- (empty file)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.java
     Fri Oct  8 12:23:17 2004
@@ -0,0 +1,136 @@
+package org.apache.beehive.controls.runtime.generator;
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
+/**
+ * The ImplInitializer class is a generated class that contains the code 
necessary to initialize
+ * a ControlBean implementation instance.
+ */
+public class ImplInitializer extends GenClass
+{
+    /**
+     * Constructs a new ImplInitializer class supporting a particular control 
bean implementation
+     * @param beanInterface the public interface associated with the bean
+     */
+    protected ImplInitializer(ControlImpl controlImpl)
+    {
+        super();
+        _controlImpl = controlImpl;
+        _controlIntf = _controlImpl.getControlInterface();
+        if (_controlImpl != null)
+        {
+            _packageName = _controlImpl.getPackage();
+            _shortName = _controlImpl.getShortName() + "Initializer";
+            _className = _packageName + "." + _shortName;
+            if (_controlImpl.getSuperClass() != null)
+                _superClass = new 
ImplInitializer(_controlImpl.getSuperClass());
+        } 
+        else
+        {
+            Class c = 
org.apache.beehive.controls.runtime.bean.ImplInitializer.class;
+            _packageName = c.getPackage().getName();
+            _className = c.getName();
+            _shortName = _className.substring(_packageName.length() + 1);
+        }
+
+        //
+        // Compute the list of impl fields that will require reflected Fields.
+        //
+        _reflectFields = new ArrayList<GenField>();
+        for (GenField genField : _controlImpl.getContexts())
+            if (needsReflection(genField))
+                _reflectFields.add(genField);
+        for (GenField genField : _controlImpl.getClients())
+            if (needsReflection(genField))
+                _reflectFields.add(genField);
+    }
+
+    /**
+     * Returns the package name of the ImplInitializer
+     */
+    public String getPackage() { return _packageName; }
+
+    /**
+     * Returns the unqualified classname of the ImplInitializer
+     */
+    public String getShortName() { return _shortName; }
+
+    /**
+     * Returns the fully qualfied classname of the ImplInitializer
+     */
+    public String getClassName() { return _className; }
+
+    /**
+     * Returns the fully qualified classname of any associated 
ClientInitializer
+     */
+    public String getClientInitializerName()
+    {
+        return _controlImpl.getClassName() + "ClientInitializer";
+    }
+
+    /**
+     * Returns the ControlBean implementation instance
+     */
+    public ControlImpl getControlImpl() { return _controlImpl; }
+
+    /**
+     * Returns the public or extension interface associated with the 
ControlBean implementation
+     */
+    public ControlInterface getControlInterface() { return _controlIntf; }
+
+    /**
+     * Returns the ImplInitializer super class for this ImplInitializer
+     */
+    public ImplInitializer getSuperClass() { return _superClass; }
+
+    /**
+     * Returns true if the initializer will use Reflection to initialize the 
field, false
+     * otherwise.
+     */
+    static public boolean needsReflection(GenField genField)
+    {
+        //
+        // Since initializers are generated into the same package as the 
initialized class,
+        // only private access fields require reflection
+        //
+        String accessModifier = genField.getAccessModifier();
+        if (accessModifier.equals("private"))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Returns the list of impl class fields that must be initialized using 
Reflection
+     */
+    public ArrayList<GenField> getReflectFields()
+    {
+        return _reflectFields;
+    }
+
+    String _packageName;
+    String _shortName;
+    String _className;
+    ControlImpl _controlImpl;
+    ControlInterface _controlIntf;
+    ImplInitializer _superClass;
+    ArrayList<GenField> _reflectFields;
+}

Added: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.vm
==============================================================================
--- (empty file)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.vm
       Fri Oct  8 12:23:17 2004
@@ -0,0 +1,273 @@
+##
+## The Velocity code generation template for the Initializer class generated 
from a Control
+## implementation class
+##
+## Copyright 2004 The Apache Software Foundation.
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+## 
+##     http://www.apache.org/licenses/LICENSE-2.0
+## 
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+##
+## $Header:$
+##
+## The following context variables are used by this template:
+##      $init - a ImplInitializer instance that defines the attributes of the 
intializer
+##
+## The actual class template apears at the end of this file, and is preceded 
by a number of
+## supporting macros that define elements of the template.
+##
+## SUPPORTING MACROS
+##
+##
+## This macro defines any static final Field values needed for field 
initialization
+##
+#macro (declareReflectFields)
+    #foreach ($field in $init.reflectFields)
+        static final Field $field.reflectField;
+    #end
+#end
+##
+## This macro initializes the value of any static final Field values for field 
initialization
+##
+#macro (initReflectFields)
+    try
+    {
+    #foreach ($field in $init.reflectFields)
+        $field.reflectField = 
${impl.className}.class.getDeclaredField("$field.name");
+        ${field.reflectField}.setAccessible(true);
+    #end
+    }
+    catch (NoSuchFieldException nsfe)
+    {
+        throw new ExceptionInInitializerError(nsfe);
+    }
+#end
+##
+## This macro declares a new event adaptor class that maps events from an 
EventSet to
+## a set of implemented handlers on a control implementation
+##
+#macro (declareEventAdaptor $adaptor)
+    #set ($eventSet = $adaptor.eventSet)
+    protected static class $adaptor.className implements $eventSet.name, 
java.io.Serializable
+    {
+        $impl.className _impl;
+
+        ${adaptor.className}($impl.className impl) { _impl = impl; }
+
+        #foreach ($event in $eventSet.events)
+            public ${event.returnType} ${event.name}(${event.argDecl}) 
$event.throwsClause
+            {
+            #if ($adaptor.hasHandler($event))
+                #if ($event.returnType != "void") return #end 
_impl.${adaptor.getHandler($event).name}(${event.argList});
+            #elseif ($event.returnType != "void")
+                return $event.defaultReturnValue;
+            #end
+            }
+        #end
+    }
+
+#end
+##
+## This macros declares any generated class that act as event adaptors between 
an event
+## source (control or context) and implementation class event handlers.
+##
+#macro (declareEventAdaptors)
+    #foreach ($context in $impl.contexts)
+        #foreach ($adaptor in $context.eventAdaptors)
+            #declareEventAdaptor($adaptor)
+        #end
+    #end
+#end
+##
+## This macro initializes any event adaptors for a nested control
+##
+#macro (initEventAdaptors $control)
+    #foreach ($adaptor in $control.eventAdaptors)
+        ${control.localName}.${adaptor.eventSet.addListenerMethod}(new 
${adaptor.className}(impl));
+    #end
+#end
+##
+## This macro defines the initialization of a contextual service
+##
+#macro (initContext $context)
+    #if 
($context.getType().equals("org.apache.beehive.controls.api.context.ControlBeanContext"))
+    $context.type $context.localName = beanContext;
+    #else
+    $context.type $context.localName = 
($context.type)beanContext.getService(${context.type}.class, null);
+    #end
+    if ($context.localName == null)
+        throw new ControlException("Contextual service $context.type is not 
available");
+    #initEventAdaptors($context)
+    #if ($init.needsReflection($context))
+    ${context.reflectField}.set(impl, $context.localName);
+    #else
+    impl.$context.name = $context.localName; 
+    #end
+#end
+##
+## This macro defines the initialization of a contextual service
+##
+#macro (resetContext $context)
+    #if ($init.needsReflection($context))
+    ${context.reflectField}.set(impl, null);
+    #else
+    impl.$context.name = null;
+    #end
+#end
+##
+## This macro defines the initialization of a event notification proxy
+##
+#macro (initEventProxy $proxy)
+    $proxy.type $proxy.localName = ($proxy.type)getEventNotifier(bean, 
${proxy.type}.class);
+    #if ($init.needsReflection($proxy))
+    ${proxy.reflectField}.set(impl, $proxy.localName);
+    #else
+    impl.$proxy.name = $proxy.localName; 
+    #end
+#end
+##
+## This macro defines the initialization method for all nested contextual 
services
+##
+#macro (declareServiceInit)
+    /**
+     * Initializes the nested contextual services required by the 
implementation
+     */
+    public void initServices(ControlBean bean, Object target)
+    {
+        $impl.className impl = ($impl.className)target;
+
+        super.initServices(bean, impl);
+
+        ControlBeanContext beanContext = bean.getControlBeanContext();
+        try
+        {
+            #foreach ($context in $impl.contexts)
+                #initContext($context)
+            #end
+        }
+        catch (RuntimeException re) { throw re; }
+        catch (Exception e)
+        {
+            throw new ControlException("Contextual service initialization 
failure", e);
+        }
+    }
+
+    /**
+     * Resets all nested contextual services instances to null
+     */
+    public void resetServices(ControlBean bean, Object target)
+    {
+        $impl.className impl = ($impl.className)target;
+
+        try
+        {
+            #foreach ($context in $impl.contexts)
+                #resetContext($context)
+            #end
+        }
+        catch (RuntimeException re) { throw re; }
+        catch (Exception e)
+        {
+            throw new ControlException("Contextual service reset failure", e);
+        }
+    }
+#end
+##
+## This macro defines the initialization method for all nested control 
references
+##
+#macro (declareControlsInit)
+    /**
+     * Initializes the nested client event proxies required by the 
implementation
+     */
+    public void initControls(ControlBean bean, Object target)
+    {
+        $impl.className impl = ($impl.className)target;
+        // DO NOT DELEGATE TO SUPERCLASS HERE.  THE CONTROL CLIENT INIT 
HIERARCHY
+        // WILL INITIALIZE ALL THE WAY DOWN TO THE BASE CLASS!
+
+        try
+        {
+            
${init.clientInitializerName}.initialize(bean.getControlBeanContext(), impl);
+        }
+        catch (RuntimeException re) { throw re; }
+        catch (Exception e)
+        {
+            throw new ControlException("Client event proxy initialization 
failure", e);
+        }
+    }
+#end
+##
+## This macro defines the initialization method for all nested event proxies
+##
+#macro (declareEventProxyInit)
+    /**
+     * Initializes the nested client event proxies required by the 
implementation
+     */
+    public void initEventProxies(ControlBean bean, Object target)
+    {
+        $impl.className impl = ($impl.className)target;
+
+        super.initEventProxies(bean, impl);
+
+        try
+        {
+            #foreach ($proxy in $impl.clients)
+                #initEventProxy($proxy)
+            #end
+        }
+        catch (RuntimeException re) { throw re; }
+        catch (Exception e)
+        {
+            throw new ControlException("Client event proxy initialization 
failure", e);
+        }
+    }
+#end
+##
+## THE CONTROL INITIALIZER CLASS TEMPLATE
+##
+package $init.package;
+
+import java.lang.reflect.Field;
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.context.ControlBeanContext;
+import org.apache.beehive.controls.runtime.bean.ControlBean;
+
+public class $init.shortName
+    #if ($init.hasSuperClass())
+             extends $init.superClass.className 
+    #else
+             extends org.apache.beehive.controls.runtime.bean.ImplInitializer
+    #end
+{
+    #if ($init.reflectFields.size() != 0)
+        #declareReflectFields()
+        static
+        {
+            #initReflectFields()
+        }
+    #end
+
+    #if ($impl.hasContexts() || $impl.hasClients())
+        #declareEventAdaptors()
+    #end
+
+    #if ($impl.hasContexts()) 
+        #declareServiceInit()
+    #end
+
+    #if ($impl.hasControls()) 
+        #declareControlsInit()
+    #end
+
+    #if ($impl.hasClients())
+        #declareEventProxyInit()
+    #end
+}

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlImplementation.java
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlImplementation.java
        (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlImplementation.java
        Fri Oct  8 12:23:17 2004
@@ -180,11 +180,11 @@
     }
 
     /**
-     * Initializes the list of EventFields that this ControlImpl should ignore 
for event handling purposes.
+     * Initializes the list of ControlFields for this ControlImpl
      */
-    protected ArrayList<EventField> initIgnoredEventFields()
+    protected ArrayList<ControlField> initControls()
     {
-        ArrayList<EventField> fields = new ArrayList<EventField>();
+        ArrayList<ControlField> fields = new ArrayList<ControlField>();
 
         if ( _implDecl == null || _implDecl.getFields() == null )
             return fields;
@@ -251,8 +251,8 @@
             {
                 // eventField == null means this field isn't interesting for 
the purposes
                 // of this processor (control impls).  However, only emit an 
error message
-                // if the field isn't on the "ignore" list.
-                if ( getIgnoredEventField(fieldName) == null )
+                // if the field isn't on a nested control
+                if ( getControlField(fieldName) == null )
                     _env.getMessager().printError(implMethod.getPosition(),
                         "Cannot find event source field: " + fieldName);
                 continue;

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlInterface.java
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlInterface.java
     (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AptControlInterface.java
     Fri Oct  8 12:23:17 2004
@@ -450,7 +450,6 @@
         {
             // TODO: optimize to not invoke default checker?
             String checkerName = checkerMirror.toString();
-            System.err.println( "@ControlInterface " + intfDecl + " checker=" 
+ checkerName );
 
             try
             {

Modified: incubator/beehive/trunk/controls/test/build.xml
==============================================================================
--- incubator/beehive/trunk/controls/test/build.xml     (original)
+++ incubator/beehive/trunk/controls/test/build.xml     Fri Oct  8 12:23:17 2004
@@ -241,6 +241,11 @@
         <property name="_build.java.tests.ran" value="true"/>
     </target>
 
+    <target name="build-test-webapp" depends="build-test-drivers" >
+        <echo message="Building webapp"/>
+           <ant dir ="./webapps" antfile="build.xml" target="build"/>
+    </target>
+
     <!-- =================================================================== 
-->
     <!-- Targets to checkin tests and detailed tests -->
     <!-- ==================================================================== 
-->
@@ -263,10 +268,10 @@
     
     <target name="run.test">
        <parallel>
+                       <echo message="start a new thread to build 
controlsWeb"/>
                <antcall target="tomcat.start"/>
                <sequential>
-                       <echo message="start a new thread to build 
controlsWeb"/>
-                       <ant dir ="./webapps" antfile="build.xml" 
target="build"/>
+                       <antcall target="build-test-webapp" />
                        <echo message="continue the new thread, wait for tomcat 
to start"/>
                        <sleep seconds="20"/>
                        <echo message="continue the new thread, deploy 
controlsWeb"/>

Modified: 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.jcs
==============================================================================
--- 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.jcs
    (original)
+++ 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.jcs
    Fri Oct  8 12:23:17 2004
@@ -1,5 +1,8 @@
 package org.apache.beehive.controls.test.controls.context;
 
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+
 import org.apache.beehive.controls.api.bean.ControlImplementation;
 import org.apache.beehive.controls.api.context.Context;
 import org.apache.beehive.controls.api.context.ControlBeanContext;
@@ -11,7 +14,7 @@
 import org.apache.beehive.controls.test.controls.util.TestContext;
 
 @ControlImplementation
-public class BaseContextImpl implements BaseContext
+public class BaseContextImpl implements BaseContext, java.io.Serializable
 { 
     @Context ControlBeanContext context;
     @Context ResourceContext resourceContext;
@@ -39,5 +42,20 @@
     protected void onRelease()
     {
         testContext.addEvent("BaseContextImpl.onRelease");
+    }
+
+    //
+    // Implement the serialization writeObject method.  By design, contextual 
services should
+    // never be serialized, and this is done by making sure that they are set 
to null prior
+    // to impl instance serialization.  This implementation of writeObject 
just verifies this,
+    // then uses the default algorithm
+    //
+    public void writeObject(ObjectOutputStream oos)
+                            throws IOException, ClassNotFoundException
+    {
+        if (context != null || resourceContext != null || testContext != null)
+            throw new RuntimeException("Contextual service(s) not reset prior 
to serialization");
+
+        oos.defaultWriteObject();
     }
 }

Modified: 
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/context/BaseContextBeanDriver.java
==============================================================================
--- 
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/context/BaseContextBeanDriver.java
        (original)
+++ 
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/context/BaseContextBeanDriver.java
        Fri Oct  8 12:23:17 2004
@@ -24,7 +24,7 @@
        /**
         * When one event raised to a bean instance
         */
-       public Report testSingleBean(BaseContextBean contextBean){
+       public Report testSingleBean(BaseContextBean contextBean, boolean 
expectCreate){
 
                Report report=new Report();
 
@@ -52,13 +52,24 @@
         {
             testContext.endContext();
         }
-        if(checkEvents(testContext.getEvents(),
+        String [] expectedEvents;
+        if (expectCreate)
+        {
+            expectedEvents = 
                     new String [] { "BaseContextImpl.onCreate", 
"BaseContextImpl.onAcquire",
-                                    "BaseContextImpl.hello kyle", 
"BaseContextImpl.onRelease" }))
+                                    "BaseContextImpl.hello kyle", 
"BaseContextImpl.onRelease" };
+        }
+        else
+        {
+            expectedEvents = 
+                    new String [] { "BaseContextImpl.onAcquire",
+                                    "BaseContextImpl.hello kyle", 
"BaseContextImpl.onRelease" };
+        }
+        if(checkEvents(testContext.getEvents(), expectedEvents))
           report.setStatus(Report.PASS);
         else{
           report.setStatus(Report.FAIL);
-                 report.setMessage(Arrays.toString(testContext.getEvents()));
+                 report.setMessage("Events received:" + 
Arrays.toString(testContext.getEvents()));
                }
 
                return report;

Modified: 
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/context/ContextTest.java
==============================================================================
--- 
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/context/ContextTest.java
      (original)
+++ 
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/context/ContextTest.java
      Fri Oct  8 12:23:17 2004
@@ -2,7 +2,13 @@
 
 import junit.framework.Assert;
 import junit.framework.TestCase;
+
 import java.beans.Beans;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
 import org.apache.beehive.controls.api.bean.ControlBean;
 import org.apache.beehive.controls.test.controls.context.BaseContextBean;
 import org.apache.beehive.controls.test.driver.context.BaseContextBeanDriver;
@@ -39,7 +45,7 @@
                        
"org.apache.beehive.controls.test.controls.context.BaseContextBean");
 
                BaseContextBeanDriver driver=new BaseContextBeanDriver();
-               Report report=driver.testSingleBean(contextBean);
+               Report report=driver.testSingleBean(contextBean, true);
 
         if (!Report.PASS.equals(report.getStatus()))
         {
@@ -86,5 +92,59 @@
             System.err.println("Exception: " + report.getExceptionStack());
             fail("testContextEventParallel failed");
         }
-       }
+    }
+
+    /**
+     * Tests serialization/deserialization of controls that use contextual 
services
+     */
+    public void testContextSerialization() throws Exception
+    {
+               BaseContextBean contextBean = (BaseContextBean)createTestBean(
+                       
"org.apache.beehive.controls.test.controls.context.BaseContextBean");
+
+        //
+        // Run the original testContextEventSingle test
+        //
+               BaseContextBeanDriver driver=new BaseContextBeanDriver();
+               Report report=driver.testSingleBean(contextBean, true);
+
+        if (!Report.PASS.equals(report.getStatus()))
+        {
+            System.err.println("Message: " + report.getMessage());
+            System.err.println("Exception: " + report.getExceptionStack());
+            fail("testContextSerialization failed");
+        }
+
+        //
+        // Serialize the test bean into a byte array
+        //
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(contextBean);
+        oos.flush();
+        byte [] byteData = baos.toByteArray();
+        baos.close();
+
+        //
+        // Deserialize the test bean from the byte array
+        //
+        ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
+        ObjectInputStream ois = new ObjectInputStream(bais);
+        contextBean = (BaseContextBean)ois.readObject();
+        bais.close();
+
+        //
+        // Repeat the test again on the deserialized bean.  In this instance, 
the
+        // onCreate event should not be received
+        //
+               driver=new BaseContextBeanDriver();
+               report=driver.testSingleBean(contextBean, false);
+
+        if (!Report.PASS.equals(report.getStatus()))
+        {
+            System.err.println("Message: " + report.getMessage());
+            System.err.println("Exception: " + report.getExceptionStack());
+            fail("testContextSerialization failed:" + report.getMessage());
+        }
+    }
 }

Reply via email to