You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2004/03/17 00:08:51 UTC

svn commit: rev 9537 - in incubator/directory/eve/trunk/eve/frontend/common/api: . src/java/org/apache/eve/event src/java/org/apache/eve/seda src/test src/test/org src/test/org/apache src/test/org/apache/eve src/test/org/apache/eve/event

Author: akarasulu
Date: Tue Mar 16 15:08:50 2004
New Revision: 9537

Added:
   incubator/directory/eve/trunk/eve/frontend/common/api/src/test/
   incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/
   incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/apache/
   incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/apache/eve/
   incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/apache/eve/event/
   incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/apache/eve/event/AbstractSubscriberTest.java   (contents, props changed)
Modified:
   incubator/directory/eve/trunk/eve/frontend/common/api/project.xml
   incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/   (props changed)
   incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/AbstractSubscriber.java
   incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/RequestEvent.java
   incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStage.java
   incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStageConfig.java
   incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/StageMonitorAdapter.java
Log:
The abstract subscriber was failing to find an inform method when subclasses
of the event type were used.  A test case was created to isolate this bug and
a fix was made to find the most specific inform method to use for event
delivery upto but not including EventObject.class and its ancestor classes. 

Changed the RequestEvent to a more specific form of Message -> Request.



Modified: incubator/directory/eve/trunk/eve/frontend/common/api/project.xml
==============================================================================
--- incubator/directory/eve/trunk/eve/frontend/common/api/project.xml	(original)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/project.xml	Tue Mar 16 15:08:50 2004
@@ -1,43 +1,43 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <project>
-    <extend>${basedir}/../../../project.xml</extend>
-    <groupId>incubator-directory</groupId>
-    <id>eve-frontend-common-api</id>
-  
-    <name>Eve Frontend Common API</name>
-    <package>org.apache.eve</package>
-    <currentVersion>SNAPSHOT</currentVersion>
-    <inceptionYear>2003</inceptionYear>
-  	
-    <shortDescription>Common APIs used by Eve's frontend</shortDescription>
-
-    <description>
-            Common APIs used by Eve's frontend.  This separate project
-            keeps common classes in one place within the various packages
-            to prevent cyclic dependencies across Eve's frontend subprojects.
-    </description>
-  	
-    <dependencies>
-        <dependency>
-            <groupId>avalon-framework</groupId>
-            <artifactId>avalon-framework-api</artifactId>
-            <version>4.1.5</version>
-            <url>http://avalon.apache.org/framework</url>
-        </dependency>
-
-        <dependency>
-            <groupId>incubator-directory</groupId>
-            <artifactId>ldap-common</artifactId>
-            <version>SNAPSHOT</version>
-            <url>http://directory.apache.org</url>
-        </dependency>
-
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>3.8.1</version>
-            <url>http://junit.org</url>
-        </dependency>
-    </dependencies>
+  <extend>${basedir}/../../../project.xml</extend>
+  <groupId>incubator-directory</groupId>
+  <id>eve-frontend-common-api</id>
+
+  <name>Eve Frontend Common API</name>
+  <package>org.apache.eve</package>
+  <currentVersion>SNAPSHOT</currentVersion>
+  <inceptionYear>2003</inceptionYear>
+
+  <shortDescription>Common APIs used by Eve's frontend</shortDescription>
+
+  <description>
+    Common APIs used by Eve's frontend.  This separate project
+    keeps common classes in one place within the various packages
+    to prevent cyclic dependencies across Eve's frontend subprojects.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.0</version>
+      <url>http://jakarta.apache.org/commons/lang</url>
+    </dependency>
+
+    <dependency>
+      <groupId>incubator-directory</groupId>
+      <artifactId>ldap-common</artifactId>
+      <version>SNAPSHOT</version>
+      <url>http://incubator.apache.org/directory/subprojects/ldap/common</url>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <url>http://junit.org</url>
+    </dependency>
+  </dependencies>
 </project>
 

Modified: incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/AbstractSubscriber.java
==============================================================================
--- incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/AbstractSubscriber.java	(original)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/AbstractSubscriber.java	Tue Mar 16 15:08:50 2004
@@ -17,8 +17,15 @@
 package org.apache.eve.event ;
 
 
+import java.util.List ;
+import java.util.HashMap ;
 import java.util.EventObject ;
+
 import java.lang.reflect.Method ;
+import java.lang.reflect.InvocationTargetException ;
+
+import org.apache.commons.lang.Validate ;
+import org.apache.commons.lang.ClassUtils ;
 
 
 /**
@@ -33,8 +40,11 @@
  */
 public class AbstractSubscriber implements Subscriber
 {
+    /** cached inform methods for subscribers */
+    private static final HashMap methods = new HashMap() ;
+
     /** monitor for this Subscriber */
-    private final SubscriberMonitor m_monitor ;
+    private final SubscriberMonitor monitor ;
     
     
     /**
@@ -42,7 +52,7 @@
      */
     public AbstractSubscriber()
     {
-        m_monitor = null ;
+        monitor = null ;
     }
     
     
@@ -53,7 +63,7 @@
      */
     public AbstractSubscriber( SubscriberMonitor monitor )
     {
-        m_monitor = monitor ;
+        this.monitor = monitor ;
     }
     
     
@@ -62,55 +72,122 @@
      */
     public void inform( EventObject event )
     {
-        inform( this, event, m_monitor ) ;
+        try
+        {
+            inform( this, event ) ;
+        }
+        catch ( Throwable t )
+        {
+            if ( monitor != null )
+            {
+                monitor.failedOnInform( this, event, t ) ;
+            }
+            else
+            {
+                System.err.println( "Failed to inform this Subscriber " + 
+                        this + " about event " + event ) ;
+                System.err.println( "To prevent the above println use a non "
+                        + "null SubscriberMonitor" ) ;
+            }
+        }
     }
     
     
     /**
-     * Calls the appropriate inform method with the proper event type.
+     * Searches for the most event type specific inform method on the target 
+     * subscriber to call and invokes that method.  The class of the event 
+     * and all its superclasses are used in succession to find a specific inform
+     * method.  If a more specific inform method other than 
+     * <code>inform(EventObject)</code> cannot be found then a 
+     * NoSuchMethodException is raised.
      * 
      * @param subscriber the subscriber to inform
      * @param event the event that is the argument to inform
-     * @param monitor the monitor to use on errors
      */
-    public static void inform( Subscriber subscriber, EventObject event, 
-                               SubscriberMonitor monitor )
+    public static void inform( Subscriber subscriber, EventObject event ) throws
+        NoSuchMethodException, IllegalAccessException, InvocationTargetException
     {
-        if ( event == null )
-        {    
-            return ;
+        Validate.notNull( subscriber, "subscriber arg cannot be null" ) ;
+        Validate.notNull( event, "event arg cannot be null" ) ;
+
+        Method method = getSpecificInformMethod( subscriber, event ) ;
+        Object params[] = { event } ; 
+        method.invoke( subscriber, params ) ;
+    }
+    
+    
+    /**
+     * Gets the specific inform method of a subscriber class that takes the
+     * event class as its sole argument.  
+     * 
+     * @param subscr the subscriber
+     * @param event the event
+     * @return the specific inform Method to invoke
+     * @throws NoSuchMethodException if an inform method other than <code>
+     *  inform(EventObject)</code> cannot be found 
+     */
+    public static Method getSpecificInformMethod( Subscriber subscr, 
+                                                  EventObject event )
+        throws NoSuchMethodException
+    {
+        Method method = null ;
+        
+        /*
+         * attempt a lookup into the signature cache to see if we can find
+         * the method there if not then we need to search for the method 
+         */
+        StringBuffer signature = new StringBuffer() ;
+        signature.append( subscr.getClass().getName() ) ;
+        signature.append( '.' ) ;
+        signature.append( "inform(" ) ;
+        signature.append( event.getClass().getName() ) ;
+        signature.append( ')' ) ;
+        
+        String key = signature.toString() ;
+        if ( methods.containsKey( key ) )
+        {
+            return ( Method ) methods.get( key ) ;
         }
         
-        Method l_method = null ;
-        Class l_paramTypes[] = new Class[1] ;
-        l_paramTypes[0] = event.getClass() ;
+        /*
+         * we could not find the method in the cache so we need to find it
+         * and add it to the cache if it exists at all  
+         */
+        List list = ClassUtils.getAllSuperclasses( event.getClass() ) ;
+        list.removeAll( ClassUtils.getAllSuperclasses( EventObject.class ) ) ;
+        list.add( 0, event.getClass() ) ;
         
-        try 
-        { 
-          /* 
-           * Look for an inform method in the current object that takes the 
-           * event subtype as a parameter
-           */ 
-          Class l_clazz = subscriber.getClass() ; 
-          l_method = l_clazz.getDeclaredMethod( "inform", l_paramTypes ) ; 
-          Object l_paramList[] = new Object[1] ; 
-          l_paramList[0] = event ; 
-          l_method.invoke( subscriber, l_paramList ) ; 
+        // there may be two EventObject class references in the list
+        while( list.contains( EventObject.class ) )
+        {    
+            list.remove( EventObject.class ) ;
         }
-        catch ( Throwable t )
+
+        Method[] all = subscr.getClass().getMethods() ;
+        for ( int ii = 0; ii < all.length; ii++ )
         {
-            if ( monitor != null )
+            method = all[ii] ;
+            
+            if ( method.getName().equals( "inform" ) )
             {
-                monitor.failedOnInform( subscriber, event, t ) ;
-            }
-            else
-            {
-                System.err.println( "Failed to inform this Subscriber " + 
-                        subscriber + " about event " + event ) ;
-                System.err.println( "To prevent the above println use a non "
-                        + "null SubscriberMonitor with this call" ) ;
+                Class[] paramTypes = method.getParameterTypes() ;
+                
+                if ( paramTypes.length == 1 )
+                {
+                    for ( int jj = 0; jj < list.size(); jj++ )
+                    {    
+                        if ( paramTypes[0] == list.get( jj ) )
+                        {
+                            methods.put( key, method ) ;
+                            return method ;
+                        }
+                    }
+                }
             }
         }
         
+        throw new NoSuchMethodException( "Could not find a more specific "
+                + "inform method other than " + subscr.getClass().getName()
+                + ".inform(EventObject)" ) ;
     }
 }

Modified: incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/RequestEvent.java
==============================================================================
--- incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/RequestEvent.java	(original)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/event/RequestEvent.java	Tue Mar 16 15:08:50 2004
@@ -18,7 +18,7 @@
 
 
 import org.apache.eve.listener.ClientKey ;
-import org.apache.ldap.common.message.Message ;
+import org.apache.ldap.common.message.Request ;
 
 
 /**
@@ -31,7 +31,7 @@
 public class RequestEvent extends ClientEvent
 {
     /** the LDAP request message */
-    private final Message request ;
+    private final Request request ;
 
     
     /**
@@ -41,7 +41,7 @@
      * @param clientKey the key of the client associated with this event
      * @param request the LDAP request message
      */
-    public RequestEvent( Object source, ClientKey clientKey, Message request )
+    public RequestEvent( Object source, ClientKey clientKey, Request request )
     {
         super( source, clientKey ) ;
         this.request = request ; 
@@ -53,7 +53,7 @@
      * 
      * @return the LDAP request message associated with this event
      */
-    public Message getRequest()
+    public Request getRequest()
     {
         return request ;
     }

Modified: incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStage.java
==============================================================================
--- incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStage.java	(original)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStage.java	Tue Mar 16 15:08:50 2004
@@ -33,7 +33,7 @@
 public class DefaultStage implements Stage
 {
     /** driver max wait/timeout in millis */
-    private static final long DRIVER_WAIT = 200 ;
+    //private static final long DRIVER_WAIT = 200 ;
     /** the configuration bean */
     protected final StageConfig m_config ;
     /** this Stage's event queue */
@@ -149,7 +149,7 @@
                     {
                         try 
                         {
-                            m_queue.wait( DRIVER_WAIT ) ;
+                            m_queue.wait() ; //DRIVER_WAIT ) ;
                         } 
                         catch( InterruptedException e ) 
                         {
@@ -246,16 +246,15 @@
      */
     public void stop() throws InterruptedException
     {
-        synchronized( m_hasStarted )
-        {
-            m_hasStarted = new Boolean( false ) ;
+        m_hasStarted = new Boolean( false ) ;
 
-            synchronized( m_activeWorkers ) 
+        while ( m_thread.isAlive() || ! m_activeWorkers.isEmpty() )
+        {
+            Thread.sleep( 100 ) ;
+            
+            synchronized( m_queue )
             {
-                while ( m_thread.isAlive() || ! m_activeWorkers.isEmpty() )
-                {
-                    Thread.sleep( 100 ) ;
-                }
+                m_queue.notifyAll() ;
             }
         }
         

Modified: incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStageConfig.java
==============================================================================
--- incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStageConfig.java	(original)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/DefaultStageConfig.java	Tue Mar 16 15:08:50 2004
@@ -18,6 +18,7 @@
 
 
 import java.util.List ;
+import java.util.ArrayList ;
 
 import org.apache.eve.thread.ThreadPool ;
 
@@ -34,7 +35,7 @@
     /** the name of this Stage */
     private final String name ;
     /** this Stage's handler */
-    private final StageHandler handler ;
+    private StageHandler handler ;
     /** the enqueue predicates for this Stage */
     private final List predicates ;
     /** the thread pool used for this Stages workers */
@@ -55,7 +56,41 @@
         this.tp = tp ;
         this.name = name ;
         this.handler = handler ;
-        this.predicates = predicates ;
+        
+        if ( predicates == null )
+        {
+            this.predicates = new ArrayList() ;
+        }
+        else
+        {    
+            this.predicates = predicates ;
+        }
+    }
+
+
+    /**
+     * Creates a default stage configuration bean.
+     * 
+     * @param name the name of this Stage
+     * @param handler this Stage's handler 
+     * @param predicates the enqueue predicates for this Stage
+     * @param tp the thread pool used for this Stages workers
+     */
+    public DefaultStageConfig( String name, List predicates, ThreadPool tp )
+    {
+        this( name, null, predicates, tp ) ;
+    }
+
+
+    /**
+     * Creates a default stage configuration bean.
+     * 
+     * @param name the name of this Stage
+     * @param tp the thread pool used for this Stage's workers
+     */
+    public DefaultStageConfig( String name, ThreadPool tp )
+    {
+        this( name, null, null, tp ) ;
     }
 
 
@@ -74,6 +109,12 @@
     public StageHandler getHandler()
     {
         return handler ;
+    }
+    
+    
+    public void setHandler( StageHandler handler )
+    {
+        this.handler = handler ;
     }
 
     

Modified: incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/StageMonitorAdapter.java
==============================================================================
--- incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/StageMonitorAdapter.java	(original)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/src/java/org/apache/eve/seda/StageMonitorAdapter.java	Tue Mar 16 15:08:50 2004
@@ -21,7 +21,8 @@
 
 
 /**
- * A do nothing adapter for a stage.
+ * A do nothing adapter for a stage.  For safty's sake this adapter throws 
+ * runtime exceptions wrapping failure exception notifications.
  *
  * @author <a href="mailto:directory-dev@incubator.apache.org">
  * Apache Directory Project</a>
@@ -105,6 +106,7 @@
      */
     public void driverFailed( Stage stage, InterruptedException fault )
     {
+        throw new RuntimeException( fault ) ;
     }
 
     
@@ -114,5 +116,6 @@
      */
     public void handlerFailed( Stage stage, EventObject event, Throwable fault )
     {
+        throw new RuntimeException( fault ) ;
     }
 }

Added: incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/apache/eve/event/AbstractSubscriberTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/eve/frontend/common/api/src/test/org/apache/eve/event/AbstractSubscriberTest.java	Tue Mar 16 15:08:50 2004
@@ -0,0 +1,137 @@
+/*
+ *   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.
+ *
+ */
+package org.apache.eve.event ;
+
+
+import java.nio.ByteBuffer ;
+import java.util.EventObject ;
+
+import org.apache.eve.listener.ClientKey ;
+
+import junit.framework.TestCase ;
+
+
+/**
+ * Tests the AbstractSubscriber class.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class AbstractSubscriberTest extends TestCase
+{
+    TestSubscriber subscriber = null ;
+    
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception
+    {
+        super.setUp() ;
+        subscriber = new TestSubscriber() ;
+    }
+
+    
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception
+    {
+        super.tearDown() ;
+        subscriber = null ;
+    }
+
+    
+    /*
+     * Class to test for void AbstractSubscriber()
+     */
+    public void testAbstractSubscriber()
+    {
+    }
+
+    
+    /*
+     * Class to test for void AbstractSubscriber(SubscriberMonitor)
+     */
+    public void testAbstractSubscriberSubscriberMonitor()
+    {
+    }
+    
+
+    /*
+     * Class to test for void inform(EventObject)
+     */
+    public void testInformEventObject()
+    {
+        EventObject e = new EventSubclass( null, null ) ;
+        subscriber.inform( e ) ;
+        subscriber.assertDelivery() ;
+        subscriber.inform( e ) ;
+        subscriber.assertDelivery() ;
+    }
+
+    
+    /*
+     * Class to test for void inform(Subscriber, EventObject, SubscriberMonitor)
+     */
+    public void testInformSubscriberEventObjectSubscriberMonitor()
+    {
+    }
+
+    
+    class EventSubclass extends InputEvent  
+    {
+        public EventSubclass( ClientKey key, ByteBuffer buf )
+        {
+            super( AbstractSubscriberTest.this, key, buf ) ;
+        }
+        
+        /* (non-Javadoc)
+         * @see org.apache.eve.event.InputEvent#claimInterest(java.lang.Object)
+         */
+        public ByteBuffer claimInterest( Object party )
+        {
+            return null ;
+        }
+
+        /* (non-Javadoc)
+         * @see org.apache.eve.event.InputEvent#releaseInterest(java.lang.Object)
+         */
+        public void releaseInterest( Object party )
+        {
+        }
+    } ;
+
+
+    class TestSubscriber extends AbstractSubscriber
+    {
+        InputEvent e = null ;
+            
+        public void assertDelivery() 
+        {
+            assertNotNull( e ) ;
+            e = null ;
+        }
+            
+        public void inform( InputEvent event )
+        {
+            assertNotNull( event ) ;
+            e = event ;
+        }
+    } ;
+
+}