Author: akarasulu
Date: Sun Jan 27 18:03:44 2008
New Revision: 615699

URL: http://svn.apache.org/viewvc?rev=615699&view=rev
Log:
changes ...

 o more cleanups
 o more documentation
 o adding client connection listener interface and plumbing for notification of
   disconnect and idling


Added:
    
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/
    
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/ClientListenerExample.java
      - copied, changed from r615542, 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/helloworld/HelloWorldHttpService.java
    
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/Main.java
   (with props)
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpClientListener.java
Modified:
    mina/asyncweb/trunk/examples/src/main/resources/log4j.properties
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpService.java
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpServiceContext.java
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/context/AbstractHttpServiceContext.java
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/DefaultHttpIoHandler.java
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/MinaTransport.java
    
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/SingleHttpSessionIoHandler.java

Copied: 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/ClientListenerExample.java
 (from r615542, 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/helloworld/HelloWorldHttpService.java)
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/ClientListenerExample.java?p2=mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/ClientListenerExample.java&p1=mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/helloworld/HelloWorldHttpService.java&r1=615542&r2=615699&rev=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/helloworld/HelloWorldHttpService.java
 (original)
+++ 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/ClientListenerExample.java
 Sun Jan 27 18:03:44 2008
@@ -17,152 +17,64 @@
  *  under the License.
  *
  */
-package org.apache.asyncweb.examples.helloworld;
+package org.apache.asyncweb.examples.listener;
+
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.nio.charset.Charset;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.mina.common.IoBuffer;
-import org.apache.asyncweb.common.HttpRequest;
-import org.apache.asyncweb.common.HttpResponseStatus;
-import org.apache.asyncweb.common.MutableHttpResponse;
-import org.apache.asyncweb.common.Cookie;
-import org.apache.asyncweb.common.DefaultHttpResponse;
 import org.apache.asyncweb.server.HttpService;
 import org.apache.asyncweb.server.HttpServiceContext;
+import org.apache.asyncweb.server.HttpClientListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 
 /**
- * A simple <code>HttpService</code> which sends "hello world"
- * responses to every request.
- *
- * Note that normally we wouldn't be generating html directly in a service :o)
- *
- * @author irvingd
+ * An <code>HttpService</code> which utilizes the HttpClientListener interface
+ * for long polling requests.
  *
+ * @author The Apache MINA Project ([EMAIL PROTECTED])
+ * @version $Rev$, $Date$
  */
-public class HelloWorldHttpService implements HttpService {
-
-    private String message = "Hello from AsyncWeb!!";
-
-    /**
-     * Sends the configured message as an HTTP response
-     */
-    public void handleRequest( HttpServiceContext context) throws Exception {
-        MutableHttpResponse response = new DefaultHttpResponse();
-
-        StringWriter buf = new StringWriter();
-        PrintWriter writer = new PrintWriter(buf);
-        writer.println("<html><body><b>Your message of the 
day:</b><br/><br/>");
-        writer.println("<h2><i>" + message + "</h2></i><br/><br/>");
-        writeHeaders(context.getRequest(), writer);
-        writer.println("<br/>");
-        writeParameters(context.getRequest(), writer);
-        writer.println("<br/>");
-        writeCookies(context.getRequest(), writer);
-        writer.flush();
-
-        IoBuffer bb = IoBuffer.allocate(1024);
-        bb.setAutoExpand(true);
-        bb.putString(buf.toString(), Charset.forName("UTF-8").newEncoder());
-        bb.flip();
-        response.setContent(bb);
-
-        response.setHeader("Pragma", "no-cache");
-        response.setHeader("Cache-Control", "no-cache");
-        response.setStatus(HttpResponseStatus.OK);
-
-        context.commitResponse(response);
-    }
-
-    /**
-     * Sets the message to return in responses.
-     * This is called for you by the framework!
-     *
-     * @param message  The message
-     */
-    public void setMessage(String message) {
-        this.message = message;
-    }
+public class ClientListenerExample implements HttpService
+{
+    private final Logger log = LoggerFactory.getLogger( 
ClientListenerExample.class );
 
+    
     /**
-     * Writes headers from the request to the specified writer
-     *
-     * @param request   The request
-     * @param writer    The writer
+     * Does nothing with the request but just listens for disconnects and
+     * connection idling.
      */
-    private void writeHeaders( HttpRequest request, PrintWriter writer) {
-        writer.println("You sent these headers with your request:<br/>");
-        writer.println("<ul>");
-        for (String headerName : request.getHeaders().keySet()) {
-            String headerValue = request.getHeader(headerName);
-            writer.print("<li>" + headerName + " = " + headerValue + "</li>");
-        }
-        writer.println("</ul>");
-    }
+    public void handleRequest( HttpServiceContext context ) throws Exception
+    {
+        final long requestTime = System.currentTimeMillis();
+        log.info( "Got request from client {} at {}", 
context.getRemoteAddress(), requestTime );
+
+        context.addClientListener( new HttpClientListener()
+        {
+            public void clientDisconnected( HttpServiceContext ctx )
+            {
+                log.info( "Client {} disconnected after {} milliSeconds", 
ctx.getRemoteAddress(),
+                        ( System.currentTimeMillis() - requestTime ) );
+            }
 
-    /**
-     * Writes cookies from the request to the specified writer
-     *
-     * @param request  The request
-     * @param writer   The writer
-     */
-    private void writeCookies(HttpRequest request, PrintWriter writer) {
-        Collection<Cookie> cookies = request.getCookies();
-        if (!cookies.isEmpty()) {
-            writer.println("You sent these cookies with your request:<br/>");
-            writer.println("<ul>");
-            for ( Cookie cookie : cookies) {
-                writer.println("<li>Name = " + cookie.getName() + " Value = "
-                        + cookie.getValue());
-                writer.println(" Path = " + cookie.getPath() + " Version = "
-                        + cookie.getVersion() + "</li>");
+            public void clientIdle( HttpServiceContext ctx, long idleTime, int 
idleCount )
+            {
+                log.info( "Client {} idle events after {} milliSeconds", 
ctx.getRemoteAddress(),
+                        ( System.currentTimeMillis() - requestTime ) );
+                log.info( "IdleTime   = {}", idleTime );
+                log.info( "IdleCount  = {}", idleCount );
             }
-            writer.println("</ul>");
-        }
+        });
     }
 
-    /**
-     * Writes request parameters to the specified writer
-     *
-     * @param request  The request
-     * @param writer   The writer
-     */
-    private void writeParameters(HttpRequest request, PrintWriter writer) {
-        if (request.getParameters().size() > 0) {
-            writer
-                    .println("You sent these parameters with your 
request:<br/><br/>");
-            writer.println("<ul>");
-
-            for (Map.Entry<String, List<String>> entry : request
-                    .getParameters().entrySet()) {
-                writer.println("<li>");
-                writer.print("'" + entry.getKey() + "' =  ");
-                for (Iterator<String> i = entry.getValue().iterator(); i
-                        .hasNext();) {
-                    String value = i.next();
-                    writer.print("'" + value + "'");
-                    if (i.hasNext()) {
-                        writer.print(", ");
-                    }
-                }
-                writer.println("</li/>");
-            }
 
-            writer.println("</ul>");
-        }
+    public void start()
+    {
+        log.info( "Started listener service. Goto 
http://localhost:9012/listener ang give it a try." );
     }
 
-    public void start() {
-        // Dont care
-    }
 
-    public void stop() {
-        // Dont care
+    public void stop()
+    {
+        log.info( "Stopped listener service." );
     }
-
-}
+}
\ No newline at end of file

Added: 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/Main.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/Main.java?rev=615699&view=auto
==============================================================================
--- 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/Main.java
 (added)
+++ 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/Main.java
 Sun Jan 27 18:03:44 2008
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.asyncweb.examples.listener;
+
+
+import org.apache.asyncweb.server.BasicServiceContainer;
+import org.apache.asyncweb.server.HttpServiceHandler;
+import org.apache.asyncweb.server.transport.mina.MinaTransport;
+import org.apache.asyncweb.server.transport.mina.DefaultHttpIoHandler;
+import org.apache.asyncweb.server.resolver.ExactMatchURIServiceResolver;
+
+
+/**
+ * An application launcher which runs the ClientListenerExample example.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Apache MINA Project</a>
+ * @version $Rev$, $Date$
+ */
+public class Main
+{
+    public static void main( String[] args ) throws Exception
+    {
+        // Setup the default container with a service handler that contains 
the helloWorldService
+        BasicServiceContainer container = new BasicServiceContainer();
+        HttpServiceHandler handler = new HttpServiceHandler();
+        handler.addHttpService( "clientListenerExample", new 
ClientListenerExample() );
+        container.addServiceFilter( handler );
+
+        // Set up a resolver for the HttpServiceHandler
+        ExactMatchURIServiceResolver resolver = new 
ExactMatchURIServiceResolver();
+        resolver.addURIMapping( "/listener", "clientListenerExample" );
+        handler.setServiceResolver( resolver );
+
+        // Create the mina transport and enable the container with it
+        MinaTransport transport = new MinaTransport();
+        container.addTransport( transport );
+        DefaultHttpIoHandler ioHandler = new DefaultHttpIoHandler();
+        ioHandler.setReadIdle( 10 );
+        transport.setIoHandler( ioHandler );
+
+        // Fire it up and go
+        container.start();
+    }
+}

Propchange: 
mina/asyncweb/trunk/examples/src/main/java/org/apache/asyncweb/examples/listener/Main.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: mina/asyncweb/trunk/examples/src/main/resources/log4j.properties
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/examples/src/main/resources/log4j.properties?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- mina/asyncweb/trunk/examples/src/main/resources/log4j.properties (original)
+++ mina/asyncweb/trunk/examples/src/main/resources/log4j.properties Sun Jan 27 
18:03:44 2008
@@ -16,7 +16,7 @@
 #  specific language governing permissions and limitations
 #  under the License.
 #
-log4j.rootLogger=WARN, stdout
+log4j.rootLogger=INFO, stdout
 log4j.logger.org.safehaus.asyncweb=INFO
 
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender

Added: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpClientListener.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpClientListener.java?rev=615699&view=auto
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpClientListener.java
 (added)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpClientListener.java
 Sun Jan 27 18:03:44 2008
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.asyncweb.server;
+
+
+/**
+ * An HTTP client connection listener. Since Asyncweb allows asynchronous
+ * handling of responses (response need not be committed in the HttpService
+ * handleRequest() method), connections can be held open for some time.  For
+ * this reason a mechanism is needed to be informed of client disconnects or
+ * for notifications when the connection idles.
+ *
+ * @author The Apache MINA Project ([EMAIL PROTECTED])
+ * @version $Rev$, $Date$
+ */
+public interface HttpClientListener
+{
+    /**
+     * Gets notification of client disconnects.
+     *
+     * @param ctx the context associated with the disconnect event
+     */
+    void clientDisconnected( HttpServiceContext ctx );
+
+
+    /**
+     * Gets notification of client idling.
+     *
+     * @param ctx the context of the client which has gone idle
+     * @param idleTime the time at which a client began idling
+     * @param idleCount the number of times we were informed of idling
+     */
+    void clientIdle( HttpServiceContext ctx, long idleTime, int idleCount );
+}

Modified: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpService.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpService.java?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpService.java
 (original)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpService.java
 Sun Jan 27 18:03:44 2008
@@ -19,18 +19,18 @@
  */
 package org.apache.asyncweb.server;
 
+
 /**
  * An application-level HTTP request processor.
  *
- * @author irvingd
- *
+ * @author The Apache MINA Project ([EMAIL PROTECTED])
+ * @version $Rev$, $Date$
  */
-public interface HttpService {
-
-    public void handleRequest(HttpServiceContext context) throws Exception;
-
-    public void start();
+public interface HttpService
+{
+    void handleRequest( HttpServiceContext context ) throws Exception;
 
-    public void stop();
+    void start();
 
+    void stop();
 }

Modified: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpServiceContext.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpServiceContext.java?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpServiceContext.java
 (original)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/HttpServiceContext.java
 Sun Jan 27 18:03:44 2008
@@ -19,40 +19,53 @@
  */
 package org.apache.asyncweb.server;
 
+
 import java.net.InetSocketAddress;
 
 import org.apache.asyncweb.common.HttpRequest;
 import org.apache.asyncweb.common.HttpResponse;
 import org.apache.asyncweb.common.HttpResponseStatus;
 
+
 /**
  * Provides conversational context between a HTTP client and a [EMAIL 
PROTECTED] HttpService}.
  *
- * @author trustin
+ * @author The Apache MINA Project ([EMAIL PROTECTED])
+ * @version $Rev$, $Date$
  */
-public interface HttpServiceContext {
-
+public interface HttpServiceContext
+{
     /**
      * Returns the socket address of the client (or last proxy).
+     *
+     * @return the socket address of the client (or last proxy)
      */
     InetSocketAddress getRemoteAddress();
 
+
     /**
      * Returns the request which is received from the client.
+     *
+     * @return the request from the client
      */
     HttpRequest getRequest();
 
+
     /**
      * Returns <tt>true</tt> if a response for the request is committed.
+     *
+     * @return true if the response has been committed, false otherwise
      */
     boolean isResponseCommitted();
 
+
     /**
      * @return  The <code>Response</code> committed to this 
<code>Request</code>,
      *          or <code>null</code> if no response has been comitted
      */
     HttpResponse getCommittedResponse();
 
+
     /**
      * Writes the specified response back to the client.
      * The response <i>must not</i> be modified after it has been
@@ -71,14 +84,17 @@
      * @param  response  The response to provide
      * @return <code>true</code> if the response was accepted
      */
-    boolean commitResponse(HttpResponse response);
+    boolean commitResponse( HttpResponse response );
+
 
     /**
      * Commits a default response with a specified [EMAIL PROTECTED] 
HttpResponseStatus}.
      *
-     * @return        <code>true</code> if the response was accepted
+     * @param status the status to return
+     * @return <code>true</code> if the response was accepted
      */
-    boolean commitResponse(HttpResponseStatus status);
+    boolean commitResponse( HttpResponseStatus status );
+
 
     /**
      * Returns the [EMAIL PROTECTED] HttpSession} which is associated with the 
client.
@@ -88,6 +104,7 @@
      */
     HttpSession getSession();
 
+
     /**
      * Returns the <code>Session</code> associated with this request.
      *
@@ -97,5 +114,11 @@
      *                is associated with the client and <code>create</code> is
      *                <code>false</code>
      */
-    HttpSession getSession(boolean create);
+    HttpSession getSession( boolean create );
+
+
+    boolean addClientListener( HttpClientListener listener );
+
+
+    boolean removeClientListener( HttpClientListener listener );
 }

Modified: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/context/AbstractHttpServiceContext.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/context/AbstractHttpServiceContext.java?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/context/AbstractHttpServiceContext.java
 (original)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/context/AbstractHttpServiceContext.java
 Sun Jan 27 18:03:44 2008
@@ -19,7 +19,9 @@
  */
 package org.apache.asyncweb.server.context;
 
+
 import java.net.InetSocketAddress;
+import java.util.ArrayList;
 
 import org.apache.asyncweb.common.HttpHeaderConstants;
 import org.apache.asyncweb.common.HttpRequest;
@@ -30,20 +32,21 @@
 import org.apache.asyncweb.server.HttpServiceContext;
 import org.apache.asyncweb.server.HttpSession;
 import org.apache.asyncweb.server.ServiceContainer;
+import org.apache.asyncweb.server.HttpClientListener;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 /**
  * A default implementation of [EMAIL PROTECTED] HttpServiceContext}.
  *
- * @author trustin
- * @version $Rev:167 $, $Date:2006-11-15 11:10:05 +0000 (수, 15 11월 2006) $
+ * @author The Apache MINA Project ([EMAIL PROTECTED])
+ * @version $Rev$, $Date$
  */
 public abstract class AbstractHttpServiceContext implements HttpServiceContext
 {
-
-    private final Logger log = LoggerFactory
-            .getLogger(AbstractHttpServiceContext.class);
+    private final Logger log = LoggerFactory.getLogger( 
AbstractHttpServiceContext.class );
 
     private final InetSocketAddress remoteAddress;
 
@@ -57,41 +60,54 @@
 
     private final ServiceContainer container;
 
-    public AbstractHttpServiceContext(InetSocketAddress remoteAddress,
-            HttpRequest request, ServiceContainer container) {
-        if (remoteAddress == null) {
-            throw new NullPointerException("remoteAddress");
+    private final ArrayList<HttpClientListener> listeners = new 
ArrayList<HttpClientListener>( 2 );
+
+
+
+    public AbstractHttpServiceContext( InetSocketAddress remoteAddress,
+                                       HttpRequest request, ServiceContainer 
container )
+    {
+        if ( remoteAddress == null )
+        {
+            throw new NullPointerException( "remoteAddress" );
         }
-        if (request == null) {
-            throw new NullPointerException("request");
+
+        if ( request == null )
+        {
+            throw new NullPointerException( "request" );
         }
-        if (container == null) {
-            throw new NullPointerException("container");
+
+        if ( container == null )
+        {
+            throw new NullPointerException( "container" );
         }
 
         this.remoteAddress = remoteAddress;
         this.request = request;
         this.container = container;
-        this.session = container.getSessionAccessor().getSession(this, false);
+        this.session = container.getSessionAccessor().getSession( this, false 
);
     }
 
-    public synchronized boolean isResponseCommitted() {
+
+    public synchronized boolean isResponseCommitted()
+    {
         return committedResponse != null;
     }
 
+
     /**
      * Commits a <code>HttpResponse</code> to this <code>Request</code>.
      *
      * @param response  The response to commit
      * @return <code>true</code> iff the response was committed
      */
-    public boolean commitResponse(HttpResponse response) {
-        synchronized (this) {
-            if (isResponseCommitted()) {
-                if (log.isDebugEnabled()) {
-                    log
-                            .info("Request already comitted to a response. 
Disposing response");
-                }
+    public boolean commitResponse( HttpResponse response )
+    {
+        synchronized ( this )
+        {
+            if ( isResponseCommitted() )
+            {
+                log.info( "Request already comitted to a response. Disposing 
response" );
                 return false;
             }
 
@@ -99,83 +115,98 @@
         }
 
         // Add the session identifier if the session was newly created.
-        if (createdSession) {
-            container.getSessionAccessor().addSessionIdentifier(this,
-                    (MutableHttpResponse) response);
+        if ( createdSession )
+        {
+            container.getSessionAccessor().addSessionIdentifier( this, ( 
MutableHttpResponse ) response );
         }
 
         // Only parsed requests can be formatted.
-        if (getRequest().getMethod() != null) {
-            container.getErrorResponseFormatter().formatResponse(getRequest(),
-                    (MutableHttpResponse) response);
+        if ( getRequest().getMethod() != null )
+        {
+            container.getErrorResponseFormatter().formatResponse( 
getRequest(), ( MutableHttpResponse ) response );
         }
 
-        if (container.isSendServerHeader()) {
-            ((MutableHttpResponse) response).setHeader(
-                    HttpHeaderConstants.KEY_SERVER, "AsyncWeb");
+        if ( container.isSendServerHeader() )
+        {
+            ( ( MutableHttpResponse ) response ).setHeader( 
HttpHeaderConstants.KEY_SERVER, "AsyncWeb" );
         }
 
         // Normalize the response.
-        ((MutableHttpResponse) response).normalize(getRequest());
+        ( ( MutableHttpResponse ) response ).normalize( getRequest() );
 
         // Override connection header if needed.
-        if (!container.getKeepAliveStrategy().keepAlive(this, response)) {
-            ((MutableHttpResponse) response).setHeader(
-                    HttpHeaderConstants.KEY_CONNECTION,
-                    HttpHeaderConstants.VALUE_CLOSE);
+        if ( ! container.getKeepAliveStrategy().keepAlive( this, response ) )
+        {
+            ( ( MutableHttpResponse ) response ).setHeader( 
HttpHeaderConstants.KEY_CONNECTION,
+                    HttpHeaderConstants.VALUE_CLOSE );
         }
 
-        boolean requiresClosure = !HttpHeaderConstants.VALUE_KEEP_ALIVE
-                .equalsIgnoreCase(response
-                        .getHeader(HttpHeaderConstants.KEY_CONNECTION));
+        boolean requiresClosure = ! HttpHeaderConstants.VALUE_KEEP_ALIVE
+                .equalsIgnoreCase( 
response.getHeader(HttpHeaderConstants.KEY_CONNECTION ) );
 
-        if (requiresClosure && log.isDebugEnabled()) {
+        if ( requiresClosure && log.isDebugEnabled() )
+        {
             log.debug("Response status: " + response.getStatus());
             log.debug("Keep-alive strategy requires closure of "
                     + getRemoteAddress());
         }
 
-        if (log.isDebugEnabled()) {
-            log.debug("Committing a response:");
-            log.debug("Status: " + response.getStatus() + ' '
-                    + response.getStatusReasonPhrase());
-            log.debug("Headers: " + response.getHeaders());
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "Committing a response:" );
+            log.debug( "Status: " + response.getStatus() + ' ' + 
response.getStatusReasonPhrase() );
+            log.debug( "Headers: " + response.getHeaders() );
         }
 
-        doWrite(requiresClosure);
-
+        doWrite( requiresClosure );
         return true;
     }
 
-    public boolean commitResponse(HttpResponseStatus status) {
+
+    public boolean commitResponse( HttpResponseStatus status )
+    {
         MutableHttpResponse response = new DefaultHttpResponse();
-        response.setStatus(status);
-        return commitResponse(response);
+        response.setStatus( status );
+        return commitResponse( response );
     }
 
-    public synchronized HttpResponse getCommittedResponse() {
+
+    public synchronized HttpResponse getCommittedResponse()
+    {
         return committedResponse;
     }
 
-    public InetSocketAddress getRemoteAddress() {
+
+    public InetSocketAddress getRemoteAddress()
+    {
         return remoteAddress;
     }
 
-    public HttpRequest getRequest() {
+
+    public HttpRequest getRequest()
+    {
         return request;
     }
 
-    public HttpSession getSession() {
-        return getSession(true);
+
+    public HttpSession getSession()
+    {
+        return getSession( true );
     }
 
-    public synchronized HttpSession getSession(boolean create) {
-        if (session != null && !session.isValid()) {
+    
+    public synchronized HttpSession getSession( boolean create )
+    {
+        if ( session != null && ! session.isValid() )
+        {
             session = null;
         }
-        if (session == null) {
-            session = container.getSessionAccessor().getSession(this, create);
-            if (create) {
+
+        if ( session == null )
+        {
+            session = container.getSessionAccessor().getSession( this, create 
);
+            if ( create )
+            {
                 createdSession = true;
             }
         }
@@ -183,5 +214,50 @@
         return session;
     }
 
-    protected abstract void doWrite(boolean requiresClosure);
+
+    protected void fireClientDisconnected()
+    {
+        ArrayList<HttpClientListener> cloned;
+        synchronized( listeners )
+        {
+            //noinspection unchecked
+            cloned = ( ArrayList<HttpClientListener> ) listeners.clone();
+        }
+
+        for ( HttpClientListener listener : cloned )
+        {
+            listener.clientDisconnected( this );
+        }
+    }
+
+
+    protected void fireClientIdle( long idleTime, int idleCount )
+    {
+        ArrayList<HttpClientListener> cloned;
+        synchronized( listeners )
+        {
+            //noinspection unchecked
+            cloned = ( ArrayList<HttpClientListener> ) listeners.clone();
+        }
+
+        for ( HttpClientListener listener : cloned )
+        {
+            listener.clientIdle( this, idleTime, idleCount );
+        }
+    }
+
+
+    public boolean addClientListener( HttpClientListener listener )
+    {
+        return listeners.add( listener );
+    }
+
+
+    public boolean removeClientListener( HttpClientListener listener )
+    {
+        return listeners != null && listeners.remove( listener );
+    }
+
+
+    protected abstract void doWrite( boolean requiresClosure );
 }

Modified: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/DefaultHttpIoHandler.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/DefaultHttpIoHandler.java?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/DefaultHttpIoHandler.java
 (original)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/DefaultHttpIoHandler.java
 Sun Jan 27 18:03:44 2008
@@ -35,6 +35,10 @@
  */
 public class DefaultHttpIoHandler extends SingleSessionIoHandlerDelegate 
implements HttpIoHandler
 {
+    /** the default idle time in seconds - 5 minutes */
+    public static final int DEFAULT_IDLE_TIME = 300;
+
+
     public DefaultHttpIoHandler()
     {
         super( new Factory() );
@@ -53,9 +57,16 @@
     }
 
 
+    public void setReadIdle( int idleTime )
+    {
+        ( ( Factory ) getFactory() ).setReadIdle( idleTime );
+    }
+
+
     private static class Factory implements SingleSessionIoHandlerFactory
     {
         private ServiceContainer container;
+        private int readIdleTime = DEFAULT_IDLE_TIME;
 
         public ServiceContainer getContainer()
         {
@@ -67,9 +78,17 @@
             this.container = container;
         }
 
+        public void setReadIdle( int idleTime )
+        {
+            this.readIdleTime = idleTime;
+        }
+
+
         public SingleSessionIoHandler getHandler( IoSession session )
         {
-            return new SingleHttpSessionIoHandler( container, session );
+            SingleHttpSessionIoHandler handler = new 
SingleHttpSessionIoHandler( container, session );
+            handler.setReadIdleTime( readIdleTime );
+            return handler;
         }
     }
 }

Modified: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/MinaTransport.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/MinaTransport.java?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/MinaTransport.java
 (original)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/MinaTransport.java
 Sun Jan 27 18:03:44 2008
@@ -46,14 +46,11 @@
  */
 public class MinaTransport implements Transport
 {
-
-    private static final Logger LOG = LoggerFactory
-            .getLogger(MinaTransport.class);
+    private static final Logger LOG = LoggerFactory.getLogger( 
MinaTransport.class );
 
     private static final int DEFAULT_PORT = 9012;
 
-    private static final int DEFAULT_IO_THREADS = Runtime.getRuntime()
-            .availableProcessors();
+    private static final int DEFAULT_IO_THREADS = 
Runtime.getRuntime().availableProcessors();
 
     private static final int DEFAULT_EVENT_THREADS = 16;
 
@@ -216,7 +213,7 @@
         }
         finally
         {
-            if ( !success )
+            if ( ! success )
             {
                 acceptor.dispose();
                 acceptor = null;

Modified: 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/SingleHttpSessionIoHandler.java
URL: 
http://svn.apache.org/viewvc/mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/SingleHttpSessionIoHandler.java?rev=615699&r1=615698&r2=615699&view=diff
==============================================================================
--- 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/SingleHttpSessionIoHandler.java
 (original)
+++ 
mina/asyncweb/trunk/server/src/main/java/org/apache/asyncweb/server/transport/mina/SingleHttpSessionIoHandler.java
 Sun Jan 27 18:03:44 2008
@@ -52,6 +52,12 @@
 import org.slf4j.LoggerFactory;
 
 
+/**
+ * The single session handler implementation.
+ *
+ * @author The Apache MINA Project ([EMAIL PROTECTED])
+ * @version $Rev$, $Date$
+ */
 public class SingleHttpSessionIoHandler implements SingleSessionIoHandler
 {
     private static final Logger LOG = LoggerFactory.getLogger( 
SingleHttpSessionIoHandler.class );
@@ -72,7 +78,7 @@
     private final RequestPipeline pipeline;
 
     /** the current context being processed */
-    private HttpServiceContext currentContext;
+    private DefaultHttpServiceContext currentContext;
 
     /** idle time for request reads */
     private int readIdleTime = DEFAULT_IDLE_TIME;
@@ -112,6 +118,11 @@
     public void sessionClosed()
     {
         LOG.info( "Connection closed" );
+
+        if ( currentContext != null )
+        {
+            currentContext.fireClientDisconnected();
+        }
     }
 
 
@@ -129,8 +140,17 @@
             //        LOG.info("Read idled out while parsing request. 
Scheduling timeout response");
             //        handleReadFailure(currentContext, 
HttpResponseStatus.REQUEST_TIMEOUT, "Timeout while reading request");
             //      } else {
-            LOG.info( "Idled with no current request. Scheduling closure when 
pipeline empties" );
 
+            if ( currentContext != null )
+            {
+                if ( IdleStatus.BOTH_IDLE == idleType || 
IdleStatus.READER_IDLE == idleType )
+                {
+                    currentContext.fireClientIdle( 
session.getLastReaderIdleTime(), session.getReaderIdleCount() );
+                }
+            }
+
+            // TODO - look further into this - it may present serious issues 
when dealing with HTTP/1.1 
+            LOG.info( "Idled with no current request. Scheduling closure when 
pipeline empties" );
             pipeline.runWhenEmpty( new Runnable()
             {
                 public void run()
@@ -249,10 +269,11 @@
     public void setReadIdleTime( int readIdleTime )
     {
         this.readIdleTime = readIdleTime;
+        session.getConfig().setReaderIdleTime( readIdleTime );
     }
 
 
-    protected HttpServiceContext createContext( HttpRequest request )
+    protected DefaultHttpServiceContext createContext( HttpRequest request )
     {
         return new DefaultHttpServiceContext( request );
     }
@@ -272,9 +293,8 @@
         public void messageReceived( NextFilter nextFilter, IoSession session, 
Object message ) throws Exception
         {
             HttpRequest request = ( HttpRequest ) message;
-            HttpServiceContext context = createContext( request );
-            currentContext = context;
-            nextFilter.messageReceived( session, context );
+            currentContext = createContext( request );
+            nextFilter.messageReceived( session, currentContext );
         }
     }
 
@@ -405,6 +425,18 @@
                 LOG.debug( "Added CLOSE future listener." );
                 future.addListener( IoFutureListener.CLOSE );
             }
+        }
+
+
+        public void fireClientIdle( long idleTime, int idleCount )
+        {
+            super.fireClientIdle( idleTime, idleCount );
+        }
+        
+
+        public void fireClientDisconnected()
+        {
+            super.fireClientDisconnected();
         }
     }
 }


Reply via email to