Author: kentam
Date: Wed Jan 19 12:17:40 2005
New Revision: 125650
URL: http://svn.apache.org/viewcvs?view=rev&rev=125650
Log:
Updated the control interceptor model to allow interceptors to pivot a control
method invocation. This means interceptors
can stop the execution of a control method and provide a return value if the
method returns a value. In the event an
interceptor pivots, caller of the method and interceptors that precedes the
pivoting interceptor in the method call
will have no knowledge of the pivot. If the method returns a value, the caller
will recieve the value provided by the
interceptor. Preceding interceptors will be notified of postInvoke or
postEvent still. Succeeding interceptors on the
other hand will have no knowledge that the method was ever called. Here is an
example of the call sequence when a control
method with 3 interceptors (I1, I2, and I3) is called:
client calls a control method -> I1.preInvoke() -> I2.preInvoke ->
I3.preInvoke() -> method.invoke()
^
|
'-------------- I1.postInvoke() <- I2.postInvoke() <-
I3.postInvoke() <----
Here what happens when I2 pivots:
client calls a control method -> I1.preInvoke() -> I2.preInvoke -----
I3.preInvoke() method.invoke()
^ |
'-------------- I1.postInvoke() <- I2.postInvoke() <-
I3.postInvoke()
An interceptor pivots by throwing an InterceptorPivotException during preInvoke
or preEvent. If the control method
returns a value, the interceptor will provide the return value by embedding it
in the exception object.
Contributor: Hoi Lam
Added:
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java
(contents, props changed)
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/generator/ControlBean.vm
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java
Modified:
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java
Url:
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java?view=diff&rev=125650&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java&r1=125649&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java&r2=125650
==============================================================================
---
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
Wed Jan 19 12:17:40 2005
@@ -41,6 +41,7 @@
import org.apache.beehive.controls.api.events.EventSet;
import org.apache.beehive.controls.api.properties.*;
import org.apache.beehive.controls.spi.svc.Interceptor;
+import org.apache.beehive.controls.spi.svc.InterceptorPivotException;
/**
* The ControlBean class is an abstract base class for the JavaBean classes
generated to support
@@ -327,11 +328,12 @@
/* package */ Object getImplementation() { return _control; }
/**
- * The preinvoke method is called before all operations on the control.
It is the basic
- * hook for logging, context initialization, resource management, and
other common
- * services
+ * The preinvoke method is called before all operations on the control.
In addition to
+ * providing a basic hook for logging, context initialization, resource
management,
+ * and other common services, it also provides a hook for interceptors.
*/
protected void preInvoke(Method m, Object [] args, String []
interceptorNames)
+ throws InterceptorPivotException
{
//
// If the implementation expects single threaded behavior and our
container does
@@ -352,7 +354,15 @@
for ( String n : interceptorNames )
{
Interceptor i = ensureInterceptor( n );
- i.preInvoke( this, m, args );
+ try
+ {
+ i.preInvoke( this, m, args );
+ }
+ catch (InterceptorPivotException ipe)
+ {
+ ipe.setInterceptorName(n);
+ throw ipe;
+ }
}
}
@@ -365,11 +375,38 @@
}
/**
- * The postInvoke method is called after all operations on the control.
It is the basic
+ * The preinvoke method is called before all operations on the control.
It is the basic
* hook for logging, context initialization, resource management, and
other common
- * services.
+ * services
+ */
+ protected void preInvoke(Method m, Object [] args)
+ {
+ try
+ {
+ preInvoke(m, args, null);
+ }
+ catch (InterceptorPivotException ipe)
+ {
+ //this will never happen because no interceptor is passed.
+ }
+ }
+
+ /**
+ * The postInvoke method is called after all operations on the control.
In addition to
+ * providing the basic hook for logging, context initialization, resource
management, and other common
+ * services, it also provides a hook for interceptors. During preInvoke,
interceptors will be
+ * called in the order that they are in the list. During postInvoke, they
will be called in the
+ * reverse order. Here is an example of the call sequence with I1, I2,
and I3 being interceptors in the list:
+ *
+ * I1.preInvoke() -> I2.preInvoke() -> I3.preInvoke() -> invoke method
+ * |
+ * I1.postInvoke() <- I2.postInvoke() <- I3.postInvoke() <---
+ *
+ * In the event that an interceptor in the list pivoted during preInvoke,
the "pivotedInterceptor"
+ * parameter indicates the interceptor that had pivoted, and the
interceptors succeeding it in the list will
+ * not be called during postInvoke.
*/
- protected void postInvoke(Method m, Object [] args, Object retval,
Throwable t, String [] interceptorNames)
+ protected void postInvoke(Method m, Object [] args, Object retval,
Throwable t, String [] interceptorNames, String pivotedInterceptor)
{
try
{
@@ -380,10 +417,15 @@
{
ControlBeanContext cbc = getControlBeanContext();
- for ( String n : interceptorNames )
+ for (int cnt = interceptorNames.length-1; cnt >= 0; cnt-- )
{
- Interceptor i = ensureInterceptor( n );
- i.postInvoke( this, m, args, retval, t );
+ String n = interceptorNames[cnt];
+ if (pivotedInterceptor == null ||
n.equals(pivotedInterceptor))
+ {
+ pivotedInterceptor = null;
+ Interceptor i = ensureInterceptor( n );
+ i.postInvoke( this, m, args, retval, t );
+ }
}
}
@@ -405,6 +447,17 @@
}
/**
+ * The postInvoke method is called after all operations on the control.
It is the basic
+ * hook for logging, context initialization, resource management, and
other common
+ * services.
+ */
+ protected void postInvoke(Method m, Object [] args, Object retval,
Throwable t)
+ {
+ postInvoke(m, args, retval, t, null, null);
+ }
+
+
+ /**
* Sets the EventNotifier for this ControlBean
*/
protected <T> void setEventNotifier(Class<T> eventSet, T notifier)
@@ -883,10 +936,10 @@
*/
static private class NullInterceptor implements Interceptor
{
- public boolean preInvoke(
org.apache.beehive.controls.api.bean.ControlBean cb, Method m, Object [] args )
{ return true; }
- public boolean postInvoke(
org.apache.beehive.controls.api.bean.ControlBean cb, Method m, Object [] args,
Object retval, Throwable t) { return true; }
- public boolean preEvent(
org.apache.beehive.controls.api.bean.ControlBean cb, Class eventSet, Method m,
Object [] args) { return true; }
- public boolean postEvent(
org.apache.beehive.controls.api.bean.ControlBean cb, Class eventSet, Method m,
Object [] args ) { return true; }
+ public void preInvoke(
org.apache.beehive.controls.api.bean.ControlBean cb, Method m, Object [] args )
{}
+ public void postInvoke(
org.apache.beehive.controls.api.bean.ControlBean cb, Method m, Object [] args,
Object retval, Throwable t) {}
+ public void preEvent( org.apache.beehive.controls.api.bean.ControlBean
cb, Class eventSet, Method m, Object [] args) {}
+ public void postEvent(
org.apache.beehive.controls.api.bean.ControlBean cb, Class eventSet, Method m,
Object [] args ) {}
}
/** BEGIN unsynchronized fields */
Modified:
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
Url:
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm?view=diff&rev=125650&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm&r1=125649&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm&r2=125650
==============================================================================
---
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
(original)
+++
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
Wed Jan 19 12:17:40 2005
@@ -110,14 +110,18 @@
#if ($returnType != "void")
$returnType retval = ${operation.defaultReturnValue};
#end
-
- #if ($operation.interceptorServiceNames.size() == 0)
- preInvoke(${operation.methodField}, argArray, null);
- #else
- preInvoke(${operation.methodField}, argArray,
_${operation.name}Interceptors);
- #end
+ #if ($operation.interceptorServiceNames.size() > 0)
+ String pivotedInterceptor = null;
+ #end
+
try
{
+ #if ($operation.interceptorServiceNames.size() == 0)
+ preInvoke(${operation.methodField}, argArray);
+ #else
+ preInvoke(${operation.methodField}, argArray,
_${operation.name}Interceptors);
+ #end
+
##
## There are two basic generation patterns:
## - standard invoke (declared on a ControlInterface)
@@ -136,6 +140,15 @@
#end
;
}
+ #if ($operation.interceptorServiceNames.size() > 0)
+ catch (org.apache.beehive.controls.spi.svc.InterceptorPivotException
ipe)
+ {
+ pivotedInterceptor = ipe.getInterceptorName();
+ #if ($returnType != "void")
+ retval = (#toObject ($returnType))ipe.getReturnValue();
+ #end
+ }
+ #end
catch (Throwable t)
{
//
@@ -185,9 +198,9 @@
Object rv = retval;
#end
#if ($operation.interceptorServiceNames.size() == 0)
- postInvoke(${operation.methodField}, argArray, rv, thrown, null);
+ postInvoke(${operation.methodField}, argArray, rv, thrown);
#else
- postInvoke(${operation.methodField}, argArray, rv, thrown,
_${operation.name}Interceptors);
+ postInvoke(${operation.methodField}, argArray, rv, thrown,
_${operation.name}Interceptors, pivotedInterceptor);
#end
}
#if ($returnType != "void")
@@ -336,11 +349,29 @@
//
if (listener != null)
{
+ #if ($event.interceptorServiceNames.size() != 0)
+ Object [] argArray = new Object[] {$event.argList};
+ String pivotedInterceptor = null;
+ try
+ {
+ preEvent($event.methodField, argArray,
${event.methodField}Interceptors);
+ #end
#if ($returnType != "void")
retval = listener.${event.name}($event.argList);
#else
listener.${event.name}($event.argList);
#end
+ #if ($event.interceptorServiceNames.size() != 0)
+ }
+ catch
(org.apache.beehive.controls.spi.svc.InterceptorPivotException ipe)
+ {
+ pivotedInterceptor = ipe.getInterceptorName();
+ #if ($returnType != "void")
+ retval = (#toObject
($returnType))ipe.getReturnValue();
+ #end
+ }
+ postEvent($event.methodField, argArray,
${event.methodField}Interceptors, pivotedInterceptor);
+ #end
}
#if ($returnType != "void")
return retval;
@@ -348,8 +379,10 @@
#else
#if ($event.interceptorServiceNames.size() != 0)
Object [] argArray = new Object[] {$event.argList};
- if (!preEvent($event.methodField, argArray,
${event.methodField}Interceptors))
- return;
+ String pivotedInterceptor = null;
+ try
+ {
+ preEvent($event.methodField, argArray,
${event.methodField}Interceptors);
#end
java.util.Iterator listenerIter = notifier.listenerIterator();
while (listenerIter.hasNext())
@@ -358,8 +391,12 @@
listener.${event.name}($event.argList);
}
#if ($event.interceptorServiceNames.size() != 0)
- if (!postEvent($event.methodField, argArray,
${event.methodField}Interceptors))
- return;
+ }
+ catch
(org.apache.beehive.controls.spi.svc.InterceptorPivotException ipe)
+ {
+ pivotedInterceptor = ipe.getInterceptorName();
+ }
+ postEvent($event.methodField, argArray,
${event.methodField}Interceptors, pivotedInterceptor);
#end
#end
}
@@ -369,30 +406,40 @@
## This macro defines the implementation of a preEvent method
##
#macro (declarePreEvent $eventSet)
- private boolean preEvent(Method method, Object[] argArray, String[]
interceptors)
+ private void preEvent(Method method, Object[] argArray, String[]
interceptors)
+ throws org.apache.beehive.controls.spi.svc.InterceptorPivotException
{
for ( String n : interceptors )
{
org.apache.beehive.controls.spi.svc.Interceptor i =
ensureInterceptor( n );
- if (!i.preEvent( ${bean.shortName}.this,
${eventSet.formalShortName}.class , method, argArray ))
- return false;
+ try
+ {
+ i.preEvent( ${bean.shortName}.this,
${eventSet.formalShortName}.class , method, argArray );
+ }
+ catch
(org.apache.beehive.controls.spi.svc.InterceptorPivotException ipe)
+ {
+ ipe.setInterceptorName(n);
+ throw ipe;
+ }
}
- return true;
}
#end
##
## This macro defines the implementation of a preEvent method
##
#macro (declarePostEvent $eventSet)
- private boolean postEvent(Method method, Object[] argArray, String[]
interceptors)
+ private void postEvent(Method method, Object[] argArray, String[]
interceptors, String pivotedInterceptor)
{
- for ( String n : interceptors )
+ for (int cnt = interceptors.length - 1; cnt >= 0; cnt--)
{
- org.apache.beehive.controls.spi.svc.Interceptor i =
ensureInterceptor( n );
- if (!i.postEvent( ${bean.shortName}.this,
${eventSet.formalShortName}.class , method, argArray ))
- return false;
+ String n = interceptors[cnt];
+ if (pivotedInterceptor == null || n.equals(pivotedInterceptor))
+ {
+ pivotedInterceptor = null;
+ org.apache.beehive.controls.spi.svc.Interceptor i =
ensureInterceptor( n );
+ i.postEvent( ${bean.shortName}.this,
${eventSet.formalShortName}.class , method, argArray );
+ }
}
- return true;
}
#end
##
Modified:
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java
Url:
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java?view=diff&rev=125650&p1=incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java&r1=125649&p2=incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java&r2=125650
==============================================================================
---
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java
(original)
+++
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java
Wed Jan 19 12:17:40 2005
@@ -41,12 +41,14 @@
public interface Interceptor
{
/** Called before a control operation is invoked */
- public boolean preInvoke( ControlBean cb, Method m, Object [] args);
+ public void preInvoke( ControlBean cb, Method m, Object [] args)
+ throws InterceptorPivotException;
/** Called after a control operation is invoked */
- public boolean postInvoke( ControlBean cb, Method m, Object [] args,
Object retval, Throwable t );
+ public void postInvoke( ControlBean cb, Method m, Object [] args, Object
retval, Throwable t );
/** Called before a control event is fired (through a client proxy) */
- public boolean preEvent( ControlBean cb, Class eventSet, Method m, Object
[] args );
+ public void preEvent( ControlBean cb, Class eventSet, Method m, Object []
args )
+ throws InterceptorPivotException;
/** Called after a control event is fired (through a client proxy) */
- public boolean postEvent( ControlBean cb, Class eventSet, Method m, Object
[] args);
+ public void postEvent( ControlBean cb, Class eventSet, Method m, Object []
args);
}
Added:
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java
Url:
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java?view=auto&rev=125650
==============================================================================
--- (empty file)
+++
incubator/beehive/trunk/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java
Wed Jan 19 12:17:40 2005
@@ -0,0 +1,110 @@
+package org.apache.beehive.controls.spi.svc;
+
+/*
+ * 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 InterceptorPivotException class declares a checked exception that is
thrown by
+ * an Interceptor upon pivoting. For example, if an interceptor wishes to
stop a method
+ * from executing further and return a value, it can throw this exception and
embed in
+ * the exception the return value that it wishes the method to return.
+ */
+public class InterceptorPivotException extends Exception
+{
+ /**
+ * Comment for <code>serialVersionUID</code>
+ */
+ private static final long serialVersionUID = 1L;
+ private Object returnValue;
+ private String interceptorName;
+
+ /**
+ * Constructs a InterceptorPivotException object with the specified
interceptor.
+ *
+ * @param interceptorName name of the interceptor that generated this
exception
+ */
+ public InterceptorPivotException(String interceptorName)
+ {
+ super();
+ this.interceptorName = interceptorName;
+ }
+
+ /**
+ * Constructs a InterceptorPivotException object with the specified
interceptor
+ * and return value for the method that is intercepted.
+ *
+ * @param interceptorName name of the interceptor that generated this
exception
+ * @param returnValue the return value of the method that is
intercepted.
+ */
+ public InterceptorPivotException(String interceptorName, Object
returnValue)
+ {
+ super();
+ this.interceptorName = interceptorName;
+ this.returnValue = returnValue;
+ }
+
+ /**
+ * Constructs a ServiceException object using the specified
interceptor, the
+ * return value for the method that is intercepted and message.
+ *
+ * @param interceptorName name of the interceptor that generated this
exception
+ * @param returnValue the return value of the method that is
intercepted.
+ * @param message The message to use.
+ */
+ public InterceptorPivotException(String interceptorName, Object
returnValue, String message)
+ {
+ super(message);
+ this.interceptorName = interceptorName;
+ this.returnValue = returnValue;
+ }
+
+ /**
+ * Constructs a ServiceException object using the specified interceptor
and
+ * a message.
+ *
+ * @param interceptorName name of the interceptor that generated this
exception
+ * @param message The message to use.
+ */
+ public InterceptorPivotException(String interceptorName, String message)
+ {
+ super(message);
+ this.interceptorName = interceptorName;
+ }
+
+ /**
+ * @return Returns the interceptorName.
+ */
+ public String getInterceptorName()
+ {
+ return interceptorName;
+ }
+ /**
+ * @return Returns the returnValue.
+ */
+ public Object getReturnValue()
+ {
+ return returnValue;
+ }
+ /**
+ * @param interceptorName The interceptorName to set.
+ */
+ public void setInterceptorName(String interceptorName)
+ {
+ this.interceptorName = interceptorName;
+ }
+}
Modified:
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java
Url:
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java?view=diff&rev=125650&p1=incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java&r1=125649&p2=incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java&r2=125650
==============================================================================
---
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java
(original)
+++
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/util/TestInterceptorContextImpl.java
Wed Jan 19 12:17:40 2005
@@ -59,22 +59,20 @@
static public TestInterceptorContextImpl.TestInterceptorContextProvider
getProvider() { return _theProvider; }
- public boolean preInvoke( ControlBean cb, Method m, Object [] args)
+ public void preInvoke( ControlBean cb, Method m, Object [] args)
{
System.out.println( "***********************" );
System.out.println( "***********************" );
System.out.println( "PREINVOKE INTERCEPTOR " );
System.out.println( "***********************" );
System.out.println( "***********************" );
-
- return true;
}
- public boolean postInvoke( ControlBean cb, Method m, Object [] args,
Object retval, Throwable t) { return true; }
+ public void postInvoke( ControlBean cb, Method m, Object [] args, Object
retval, Throwable t) {}
/** Called before a control event is fired (through a client proxy) */
- public boolean preEvent( ControlBean cb, Class eventSet, Method m, Object
[] args) { return true; }
+ public void preEvent( ControlBean cb, Class eventSet, Method m, Object []
args) {}
/** Called after a control event is fired (through a client proxy) */
- public boolean postEvent( ControlBean cb, Class eventSet, Method m, Object
[] args) { return true; }
+ public void postEvent( ControlBean cb, Class eventSet, Method m, Object []
args) {}
}