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