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 2003/12/06 07:12:30 UTC

svn commit: rev 1368 - in incubator/directory/ldap/trunk/eve/frontend/listener: . impl impl/src impl/src/java impl/src/java/org impl/src/java/org/apache impl/src/java/org/apache/eve impl/src/java/org/apache/eve/listener spi spi/src spi/src/java spi/src/java/org spi/src/java/org/apache spi/src/java/org/apache/eve spi/src/java/org/apache/eve/listener

Author: akarasulu
Date: Fri Dec  5 22:12:30 2003
New Revision: 1368

Added:
   incubator/directory/ldap/trunk/eve/frontend/listener/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/apache/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/apache/eve/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/apache/eve/listener/
   incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/apache/eve/listener/NonBlockingListenerManager.java
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/ListenerManager.java
   incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/ServerListener.java
Log:
Adding the listener code.


Added: incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/apache/eve/listener/NonBlockingListenerManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/eve/frontend/listener/impl/src/java/org/apache/eve/listener/NonBlockingListenerManager.java	Fri Dec  5 22:12:30 2003
@@ -0,0 +1,304 @@
+/*
+
+ ============================================================================
+                   The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+    this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+    include  the following  acknowledgment:  "This product includes  software
+    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+    Alternately, this  acknowledgment may  appear in the software itself,  if
+    and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Jakarta", "Apache Directory Project", "Apache Eve" and
+    "Apache Software Foundation"  must not be used to endorse or promote
+    products derived  from this  software without  prior written
+    permission. For written permission, please contact apache@apache.org.
+
+ 5. Products  derived from this software may not  be called "Apache", nor may
+    "Apache" appear  in their name,  without prior written permission  of the
+    Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software  consists of voluntary contributions made  by many individuals
+ on  behalf of the Apache Software  Foundation. For more  information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+package org.apache.eve.listener ;
+
+
+import java.util.EventObject;
+import java.util.Set ;
+import java.util.HashSet ;
+import java.util.Iterator ;
+import java.io.IOException ;
+import java.net.InetSocketAddress ;
+
+import java.nio.channels.Selector ;
+import java.nio.channels.SelectionKey ;
+import java.nio.channels.SocketChannel ;
+import java.nio.channels.ServerSocketChannel ;
+
+import org.apache.avalon.framework.activity.Startable ;
+import org.apache.avalon.framework.activity.Initializable ;
+import org.apache.avalon.framework.logger.AbstractLogEnabled ;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager ;
+import org.apache.avalon.framework.service.Serviceable ;
+
+import org.apache.eve.event.DisconnectSubscriber;
+import org.apache.eve.event.EventRouter ;
+import org.apache.eve.event.ConnectEvent ;
+import org.apache.eve.event.DisconnectEvent ;
+
+
+/**
+ * A listener manager that uses non-blocking NIO based constructs to detect
+ * client connections on server socket listeners.
+ * 
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author$
+ * @version $Revision$
+ */
+public class NonBlockingListenerManager extends AbstractLogEnabled
+    implements
+	DisconnectSubscriber,
+    ListenerManager,
+    Initializable, 
+	Serviceable,
+    Startable, 
+    Runnable
+{
+    /** the thread driving this Runnable */ 
+    private Thread m_thread = null ;
+    /** parameter used to politely stop running thread */
+    private Boolean m_hasStarted = null ;
+    /** event manager used to decouple source to sink relationships */
+    private EventRouter m_router ;
+    /** selector used to select a acceptable socket channel */
+    private Selector m_selector = null ;
+    /** the client keys for accepted connections */
+    private Set m_clients = new HashSet() ; 
+    
+    
+    /**
+     * @see org.apache.eve.listener.ListenerManager#register(org.apache.eve.
+     * listener.ServerListener)
+     */
+    public void register( ServerListener a_listener ) throws IOException
+    {
+        ServerSocketChannel l_channel = ServerSocketChannel.open() ;
+        InetSocketAddress l_address = new InetSocketAddress( 
+                a_listener.getAddress(), 
+                a_listener.getPort() ) ;
+        l_channel.socket().bind( l_address, a_listener.getBacklog() ) ;
+        l_channel.configureBlocking( false ) ;
+        l_channel.register( m_selector, SelectionKey.OP_ACCEPT, a_listener ) ;
+    }
+    
+    
+    /**
+     * @see org.apache.eve.listener.ListenerManager#unregister(org.apache.eve.
+     * listener.ServerListener)
+     */
+    public void unregister( ServerListener a_listener ) throws IOException
+    {
+        SelectionKey l_key = null ;
+        Iterator l_keys = m_selector.keys().iterator() ;
+        
+        while ( l_keys.hasNext() )
+        {
+            l_key = ( SelectionKey ) l_keys.next() ;
+            if ( l_key.attachment().equals( a_listener ) )
+            {
+                break ;
+            }
+        }
+
+        l_key.channel().close() ;
+        l_key.cancel() ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // DisconnectSubscriber Implementation
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * Disconnects a client by removing the clientKey from the listener.
+     * 
+     * @param an_event the disconnect event
+     */
+    public void inform( DisconnectEvent an_event )
+    {
+        m_clients.remove( an_event.getClientKey() ) ;
+        
+        try
+        {
+            an_event.getClientKey().expire() ;
+        }
+        catch ( IOException e ) 
+        {
+            getLogger().error( "Could not properly expire client & close", e ) ;
+        }
+    }
+    
+    
+    public void inform( EventObject an_event )
+    {
+        inform( ( DisconnectEvent ) an_event ) ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // Runnable Implementation
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * @see java.lang.Runnable#run()
+     */
+    public void run()
+    {
+        while ( m_hasStarted.booleanValue() ) 
+        {
+            int l_count = 0 ;
+            
+            try
+            {
+                if ( 0 == ( l_count = m_selector.select( 100 ) ) )
+                {
+                    continue ;
+                }
+            } 
+            catch( IOException e )
+            {
+                getLogger().error( "Failure on select()", e ) ;
+                continue ;
+            }
+            
+            
+            Iterator l_list = m_selector.selectedKeys().iterator() ;
+            while ( l_list.hasNext() )
+            {
+                SelectionKey l_key = ( SelectionKey ) l_list.next() ;
+                
+                if ( l_key.isAcceptable() )
+                {
+                    SocketChannel l_channel = null ;
+                    ServerSocketChannel l_server = ( ServerSocketChannel )
+                        l_key.channel() ;
+                    
+                    try
+                    {
+                        l_channel = l_server.accept() ;
+                    }
+                    catch ( IOException e )
+                    {
+                        getLogger().error( "Failure on accept()", e ) ;
+                        continue ;
+                    }
+                    
+                    ClientKey l_clientKey = 
+                        new ClientKey( l_channel.socket() ) ;
+                    ConnectEvent l_event = 
+                        new ConnectEvent( this, l_clientKey ) ;
+                    m_router.publish( l_event ) ;
+                }
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Life Cycle Methods
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * Starts up this module.
+     * 
+     * @see org.apache.avalon.framework.activity.Startable#start()
+     */
+    public void start() throws Exception
+    {
+        synchronized( m_hasStarted )
+        {
+            if ( m_hasStarted.booleanValue() )
+            {
+                throw new IllegalStateException( "Already started!" ) ;
+            }
+            
+            m_hasStarted = new Boolean( true ) ;
+            m_thread = new Thread( this ) ;
+            m_thread.start() ;
+        }
+    }
+    
+    
+    /**
+     * Blocks calling thread until this module gracefully stops.
+     * 
+     * @see org.apache.avalon.framework.activity.Startable#stop()
+     */
+    public void stop() throws Exception
+    {
+        synchronized( m_hasStarted )
+        {
+            m_hasStarted = new Boolean( false ) ;
+            
+            while ( m_thread.isAlive() )
+            {
+                Thread.sleep( 100 ) ;
+            }
+        }
+    }
+    
+    
+    /**
+     * @avalon.dependency type="org.apache.eve.EventRouter"
+     *         key="event-router" version="1.0" 
+     * @see org.apache.avalon.framework.service.Serviceable#service(
+     * org.apache.avalon.framework.service.ServiceManager)
+     */
+    public void service( ServiceManager a_manager )
+    	throws ServiceException
+    {
+       m_router = ( EventRouter ) a_manager.lookup( "event-router" ) ;
+    }
+    
+    
+    /**
+     * @see org.apache.avalon.framework.activity.Initializable#initialize()
+     */
+    public void initialize() throws Exception
+    {
+        m_hasStarted = new Boolean( false ) ;
+        m_selector = Selector.open() ;
+        m_router.subscribe( DisconnectEvent.class, null, this ) ;
+    }
+}

Added: incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/ListenerManager.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/ListenerManager.java	Fri Dec  5 22:12:30 2003
@@ -0,0 +1,82 @@
+/*
+
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Eve Directory Server", "Apache Directory Project", "Apache Eve" 
+	and "Apache Software Foundation"  must not be used to endorse or promote
+	products derived  from this  software without  prior written
+	permission. For written permission, please contact apache@apache.org.
+
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software  consists of voluntary contributions made  by many individuals
+ on  behalf of the Apache Software  Foundation. For more  information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+package org.apache.eve.listener ;
+
+
+import java.io.IOException ;
+
+import org.apache.eve.event.DisconnectSubscriber ;
+
+
+/**
+ * Manages a set of server listeners.
+ * 
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author $Author$
+ * @version $Revision$
+ */
+public interface ListenerManager extends DisconnectSubscriber
+{
+    /**
+     * Registers a server listener.
+     * 
+     * @param a_listener the listener to register
+     * @throws IOException if there is a problem binding a listener
+     */
+    public void register( ServerListener a_listener ) throws IOException ;
+    
+    /**
+     * Unregisters a server listener.
+     * 
+     * @param a_listener the listener to unregister
+     * @throws IOException if there is a problem binding a listener
+     */
+    public void unregister( ServerListener a_listener ) throws IOException ;
+}

Added: incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/ServerListener.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/eve/frontend/listener/spi/src/java/org/apache/eve/listener/ServerListener.java	Fri Dec  5 22:12:30 2003
@@ -0,0 +1,91 @@
+/*
+
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Eve Directory Server", "Apache Directory Project", "Apache Eve" 
+	and "Apache Software Foundation"  must not be used to endorse or promote
+	products derived  from this  software without  prior written
+	permission. For written permission, please contact apache@apache.org.
+
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software  consists of voluntary contributions made  by many individuals
+ on  behalf of the Apache Software  Foundation. For more  information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+package org.apache.eve.listener ;
+
+
+
+/**
+ * A server listener specification interface.
+ */
+public interface ServerListener
+{
+    /** role of this service interface */
+    public static final String ROLE = ServerListener.class.getName() ;
+
+    /**
+     * Gets the server socket backlog for this ServerListener
+     *
+     * @return client connection backlog
+     */
+    public int getBacklog() ;
+
+    /**
+     * Gets the TCP port number this ServerListener listens on.
+     *
+     * @return the tcp port number
+     */
+    public int getPort() ;
+
+    /**
+     * Gets the ip interface address this ServerListener listens on.
+     *
+     * @return the ip address octets as a String i.e. 127.0.0.1
+     */
+    public String getAddress() ;
+
+    /**
+     * Gets the LDAP URL for this ServerListener using the specified ip address
+     * and the tcp port number listened to.  The ipaddress is resolved to a host
+     * name.
+     *
+     * @return the LDAP URL like so ldap://localhost:389
+     */
+    public String getURL() ;
+}