You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tr...@apache.org on 2008/04/09 13:34:36 UTC

svn commit: r646276 - in /mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive: KeepAliveFilter.java KeepAlivePolicy.java KeepAliveRequestTimeoutHandler.java

Author: trustin
Date: Wed Apr  9 04:34:35 2008
New Revision: 646276

URL: http://svn.apache.org/viewvc?rev=646276&view=rev
Log:
Resolved issue: DIRMINA-568 - Improve KeepAliveFilter to provide customizable timeout handler.
* Added KeepAliveRequestTimeoutHandler

Added:
    mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java   (with props)
Removed:
    mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAlivePolicy.java
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveFilter.java

Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveFilter.java?rev=646276&r1=646275&r2=646276&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveFilter.java Wed Apr  9 04:34:35 2008
@@ -30,8 +30,6 @@
 import org.apache.mina.common.IoSession;
 import org.apache.mina.common.IoSessionConfig;
 import org.apache.mina.common.WriteRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * An {@link IoFilter} that sends a keep-alive request on
@@ -65,8 +63,9 @@
  * <td>You want a keep-alive request is sent when the reader is idle.
  * Once the request is sent, the response for the request should be
  * received within <tt>keepAliveRequestTimeout</tt> seconds.  Otherwise,
- * the specified {@link KeepAlivePolicy} will be enforced.  If a keep-alive
- * request is received, its response also should be sent back.</td>
+ * the specified {@link KeepAliveRequestTimeoutHandler} will be invoked.
+ * If a keep-alive request is received, its response also should be sent back.
+ * </td>
  * <td>Both {@link KeepAliveMessageFactory#getRequest(IoSession)} and
  * {@link KeepAliveMessageFactory#getResponse(IoSession, Object)} must
  * return a non-<tt>null</tt>.</td>
@@ -80,8 +79,10 @@
  * </td>
  * <td>Both {@link KeepAliveMessageFactory#getRequest(IoSession)} and
  * {@link KeepAliveMessageFactory#getResponse(IoSession, Object)} must
- * return a non-<tt>null</tt>, and the <tt>policy</tt> property
- * should be set to {@link KeepAlivePolicy#OFF} or {@link KeepAlivePolicy#LOG}.
+ * return a non-<tt>null</tt>, and the <tt>timeoutHandler</tt> property
+ * should be set to {@link KeepAliveRequestTimeoutHandler#NOOP},
+ * {@link KeepAliveRequestTimeoutHandler#LOG} or the custom {@link KeepAliveRequestTimeoutHandler}
+ * implementation that doesn't affect the session state nor throw an exception.
  * </td>
  * </tr>
  * <tr valign="top">
@@ -99,8 +100,8 @@
  * <td>{@link KeepAliveMessageFactory#getRequest(IoSession)} must return
  * a non-<tt>null</tt>,
  * {@link KeepAliveMessageFactory#getResponse(IoSession, Object)} must
- * return <tt>null</tt> and the {@link KeepAlivePolicy} must be set to
- * {@link KeepAlivePolicy#OFF}.</td>
+ * return <tt>null</tt> and the <tt>timeoutHandler</tt> must be set to
+ * {@link KeepAliveRequestTimeoutHandler#DEAF_SPEAKER}.</td>
  * </tr>
  * <tr valign="top">
  * <td>Silent Listener</td>
@@ -116,12 +117,22 @@
  * {@link KeepAliveMessageFactory#isResponse(IoSession, Object)} properly
  * whatever case you chose.
  *
- * <h2>Enforcing a policy</h2>
+ * <h2>Handling timeout</h2>
+ *
+ * {@link KeepAliveFilter} will notify its {@link KeepAliveRequestTimeoutHandler}
+ * when {@link KeepAliveFilter} didn't receive the response message for a sent
+ * keep-alive message.  The default handler is {@link KeepAliveRequestTimeoutHandler#CLOSE},
+ * but you can use other presets such as {@link KeepAliveRequestTimeoutHandler#NOOP},
+ * {@link KeepAliveRequestTimeoutHandler#LOG} or {@link KeepAliveRequestTimeoutHandler#EXCEPTION}.
+ * You can even implement your own handler.
  *
- * You can enforce a predefined policy by specifying a {@link KeepAlivePolicy}.
- * The default policy is {@link KeepAlivePolicy#CLOSE}.  Setting the policy
- * to {@link KeepAlivePolicy#OFF} stops this filter from waiting for response
- * messages and therefore disables <tt>keepAliveRequestTimeout</tt> property.
+ * <h3>Special handler: {@link KeepAliveRequestTimeoutHandler#DEAF_SPEAKER}</h3>
+ *
+ * {@link KeepAliveRequestTimeoutHandler#DEAF_SPEAKER} is a special handler which is
+ * dedicated for the 'deaf speaker' mode mentioned above.  Setting the
+ * <tt>timeoutHandler</tt> property to {@link KeepAliveRequestTimeoutHandler#DEAF_SPEAKER}
+ * stops this filter from waiting for response messages and therefore disables
+ * response timeout detection.
  *
  * @author The Apache MINA Project (dev@mina.apache.org)
  * @version $Rev$, $Date$
@@ -133,32 +144,30 @@
 
     private final KeepAliveMessageFactory messageFactory;
     private final IdleStatus interestedIdleStatus;
-    private volatile KeepAlivePolicy policy;
-    private volatile int keepAliveRequestInterval;
-    private volatile int keepAliveRequestTimeout;
+    private volatile KeepAliveRequestTimeoutHandler requestTimeoutHandler;
+    private volatile int requestInterval;
+    private volatile int requestTimeout;
     private volatile boolean forwardEvent;
 
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
     /**
      * Creates a new instance with the default properties.
      * The default property values are:
      * <ul>
      * <li><tt>interestedIdleStatus</tt> - {@link IdleStatus#READER_IDLE}</li>
-     * <li><tt>policy</tt> = {@link KeepAlivePolicy#CLOSE}</li>
+     * <li><tt>policy</tt> = {@link KeepAliveRequestTimeoutHandler#CLOSE}</li>
      * <li><tt>keepAliveRequestInterval</tt> - 60 (seconds)</li>
      * <li><tt>keepAliveRequestTimeout</tt> - 30 (seconds)</li>
      * </ul>
      */
     public KeepAliveFilter(KeepAliveMessageFactory messageFactory) {
-        this(messageFactory, IdleStatus.READER_IDLE, KeepAlivePolicy.CLOSE);
+        this(messageFactory, IdleStatus.READER_IDLE, KeepAliveRequestTimeoutHandler.CLOSE);
     }
 
     /**
      * Creates a new instance with the default properties.
      * The default property values are:
      * <ul>
-     * <li><tt>policy</tt> = {@link KeepAlivePolicy#CLOSE}</li>
+     * <li><tt>policy</tt> = {@link KeepAliveRequestTimeoutHandler#CLOSE}</li>
      * <li><tt>keepAliveRequestInterval</tt> - 60 (seconds)</li>
      * <li><tt>keepAliveRequestTimeout</tt> - 30 (seconds)</li>
      * </ul>
@@ -166,7 +175,7 @@
     public KeepAliveFilter(
             KeepAliveMessageFactory messageFactory,
             IdleStatus interestedIdleStatus) {
-        this(messageFactory, interestedIdleStatus, KeepAlivePolicy.CLOSE, 60, 30);
+        this(messageFactory, interestedIdleStatus, KeepAliveRequestTimeoutHandler.CLOSE, 60, 30);
     }
 
     /**
@@ -179,7 +188,7 @@
      * </ul>
      */
     public KeepAliveFilter(
-            KeepAliveMessageFactory messageFactory, KeepAlivePolicy policy) {
+            KeepAliveMessageFactory messageFactory, KeepAliveRequestTimeoutHandler policy) {
         this(messageFactory, IdleStatus.READER_IDLE, policy, 60, 30);
     }
 
@@ -193,7 +202,7 @@
      */
     public KeepAliveFilter(
             KeepAliveMessageFactory messageFactory,
-            IdleStatus interestedIdleStatus, KeepAlivePolicy policy) {
+            IdleStatus interestedIdleStatus, KeepAliveRequestTimeoutHandler policy) {
         this(messageFactory, interestedIdleStatus, policy, 60, 30);
     }
 
@@ -202,7 +211,7 @@
      */
     public KeepAliveFilter(
             KeepAliveMessageFactory messageFactory,
-            IdleStatus interestedIdleStatus, KeepAlivePolicy policy,
+            IdleStatus interestedIdleStatus, KeepAliveRequestTimeoutHandler policy,
             int keepAliveRequestInterval, int keepAliveRequestTimeout) {
         if (messageFactory == null) {
             throw new NullPointerException("messageFactory");
@@ -216,51 +225,51 @@
 
         this.messageFactory = messageFactory;
         this.interestedIdleStatus = interestedIdleStatus;
-        this.policy = policy;
+        requestTimeoutHandler = policy;
 
-        setKeepAliveRequestInterval(keepAliveRequestInterval);
-        setKeepAliveRequestTimeout(keepAliveRequestTimeout);
+        setRequestInterval(keepAliveRequestInterval);
+        setRequestTimeout(keepAliveRequestTimeout);
     }
 
     public IdleStatus getInterestedIdleStatus() {
         return interestedIdleStatus;
     }
 
-    public KeepAlivePolicy getPolicy() {
-        return policy;
+    public KeepAliveRequestTimeoutHandler getRequestTimeoutHandler() {
+        return requestTimeoutHandler;
     }
 
-    public void setPolicy(KeepAlivePolicy policy) {
-        if (policy == null) {
-            throw new NullPointerException("policy");
+    public void setRequestTimeoutHandler(KeepAliveRequestTimeoutHandler timeoutHandler) {
+        if (timeoutHandler == null) {
+            throw new NullPointerException("timeoutHandler");
         }
-        this.policy = policy;
+        requestTimeoutHandler = timeoutHandler;
     }
 
-    public int getKeepAliveRequestInterval() {
-        return keepAliveRequestInterval;
+    public int getRequestInterval() {
+        return requestInterval;
     }
 
-    public void setKeepAliveRequestInterval(int keepAliveRequestInterval) {
+    public void setRequestInterval(int keepAliveRequestInterval) {
         if (keepAliveRequestInterval <= 0) {
             throw new IllegalArgumentException(
                     "keepAliveRequestInterval must be a positive integer: " +
                     keepAliveRequestInterval);
         }
-        this.keepAliveRequestInterval = keepAliveRequestInterval;
+        requestInterval = keepAliveRequestInterval;
     }
 
-    public int getKeepAliveRequestTimeout() {
-        return keepAliveRequestTimeout;
+    public int getRequestTimeout() {
+        return requestTimeout;
     }
 
-    public void setKeepAliveRequestTimeout(int keepAliveRequestTimeout) {
+    public void setRequestTimeout(int keepAliveRequestTimeout) {
         if (keepAliveRequestTimeout <= 0) {
             throw new IllegalArgumentException(
                     "keepAliveRequestTimeout must be a positive integer: " +
                     keepAliveRequestTimeout);
         }
-        this.keepAliveRequestTimeout = keepAliveRequestTimeout;
+        requestTimeout = keepAliveRequestTimeout;
     }
 
     public KeepAliveMessageFactory getMessageFactory() {
@@ -353,7 +362,7 @@
 
                     // If policy is OFF, there's no need to wait for
                     // the response.
-                    if (getPolicy() != KeepAlivePolicy.OFF) {
+                    if (getRequestTimeoutHandler() != KeepAliveRequestTimeoutHandler.DEAF_SPEAKER) {
                         markStatus(session);
                     } else {
                         resetStatus(session);
@@ -363,7 +372,9 @@
                 handlePingTimeout(session);
             }
         } else if (status == IdleStatus.READER_IDLE) {
-            handlePingTimeout(session);
+            if (session.containsAttribute(WAITING_FOR_RESPONSE)) {
+                handlePingTimeout(session);
+            }
         }
 
         if (forwardEvent) {
@@ -371,48 +382,27 @@
         }
     }
 
-    private void handlePingTimeout(IoSession session) {
+    private void handlePingTimeout(IoSession session) throws Exception {
         resetStatus(session);
-        switch (getPolicy()) {
-        case OFF:
-            break;
-        case LOG:
-            logTimeout();
-            break;
-        case EXCEPTION:
-            throw new KeepAliveTimeoutException(
-                    getTimeoutMessage());
-        case CLOSE:
-            logTimeout();
-            session.close();
-            break;
-        default:
-            throw new InternalError();
-        }
-    }
-
-    private void logTimeout() {
-        if (logger.isWarnEnabled()) {
-            logger.warn(getTimeoutMessage());
+        KeepAliveRequestTimeoutHandler handler = getRequestTimeoutHandler();
+        if (handler == KeepAliveRequestTimeoutHandler.DEAF_SPEAKER) {
+            return;
         }
-    }
 
-    private String getTimeoutMessage() {
-        return "Keep-alive response message was not received within " +
-        getKeepAliveRequestTimeout() + " second(s).";
+        handler.keepAliveRequestTimedOut(this, session);
     }
 
     private void markStatus(IoSession session) {
         session.getConfig().setIdleTime(interestedIdleStatus, 0);
-        session.getConfig().setIdleTime(
-                IdleStatus.READER_IDLE, getKeepAliveRequestTimeout());
+        session.getConfig().setReaderIdleTime(getRequestTimeout());
         session.setAttribute(WAITING_FOR_RESPONSE);
     }
 
     private void resetStatus(IoSession session) {
-        session.getConfig().setIdleTime(IdleStatus.READER_IDLE, 0);
+        session.getConfig().setReaderIdleTime(0);
+        session.getConfig().setWriterIdleTime(0);
         session.getConfig().setIdleTime(
-                interestedIdleStatus, getKeepAliveRequestInterval());
+                interestedIdleStatus, getRequestInterval());
         session.removeAttribute(WAITING_FOR_RESPONSE);
     }
 

Added: mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java?rev=646276&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java Wed Apr  9 04:34:35 2008
@@ -0,0 +1,101 @@
+/*
+ *  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.mina.filter.keepalive;
+
+import org.apache.mina.common.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tells {@link KeepAliveFilter} what to do when a keep-alive response message
+ * was not received within a certain timeout.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface KeepAliveRequestTimeoutHandler {
+    /**
+     * Do nothing.
+     */
+    static KeepAliveRequestTimeoutHandler NOOP = new KeepAliveRequestTimeoutHandler() {
+        public void keepAliveRequestTimedOut(
+                KeepAliveFilter filter, IoSession session) throws Exception {
+            // Do nothing.
+        }
+    };
+
+    /**
+     * Logs a warning message, but doesn't do anything else.
+     */
+    static KeepAliveRequestTimeoutHandler LOG = new KeepAliveRequestTimeoutHandler() {
+        private final Logger log =
+            LoggerFactory.getLogger(KeepAliveFilter.class);
+
+        public void keepAliveRequestTimedOut(
+                KeepAliveFilter filter, IoSession session) throws Exception {
+            log.warn("A keep-alive response message was not received within " +
+                    "{} second(s).", filter.getRequestTimeout());
+        }
+    };
+
+    /**
+     * Throws a {@link KeepAliveTimeoutException}.
+     */
+    static KeepAliveRequestTimeoutHandler EXCEPTION = new KeepAliveRequestTimeoutHandler() {
+        public void keepAliveRequestTimedOut(
+                KeepAliveFilter filter, IoSession session) throws Exception {
+            throw new KeepAliveTimeoutException(
+                    "A keep-alive response message was not received within " +
+                    filter.getRequestTimeout() + " second(s).");
+        }
+    };
+
+    /**
+     * Closes the connection after logging.
+     */
+    static KeepAliveRequestTimeoutHandler CLOSE = new KeepAliveRequestTimeoutHandler() {
+        private final Logger log =
+            LoggerFactory.getLogger(KeepAliveFilter.class);
+
+        public void keepAliveRequestTimedOut(
+                KeepAliveFilter filter, IoSession session) throws Exception {
+            log.warn("Closing the session because a keep-alive response " +
+                    "message was not received within {} second(s).",
+                    filter.getRequestTimeout());
+            session.close();
+        }
+    };
+
+    /**
+     * A special handler for the 'deaf speaker' mode.
+     */
+    static KeepAliveRequestTimeoutHandler DEAF_SPEAKER = new KeepAliveRequestTimeoutHandler() {
+        public void keepAliveRequestTimedOut(
+                KeepAliveFilter filter, IoSession session) throws Exception {
+            throw new Error("Shouldn't be invoked.  Please file a bug report.");
+        }
+    };
+
+    /**
+     * Invoked when {@link KeepAliveFilter} couldn't receive the response for
+     * the sent keep alive message.
+     */
+    void keepAliveRequestTimedOut(KeepAliveFilter filter, IoSession session) throws Exception;
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/filter/keepalive/KeepAliveRequestTimeoutHandler.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date