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) {}
 }
 

Reply via email to