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