Author: markt
Date: Mon Jun 27 22:13:39 2011
New Revision: 1140347

URL: http://svn.apache.org/viewvc?rev=1140347&view=rev
Log:
Use a more reliable method to expire sessions.

Modified:
    tomcat/trunk/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java
    tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml

Modified: 
tomcat/trunk/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java?rev=1140347&r1=1140346&r2=1140347&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java 
(original)
+++ 
tomcat/trunk/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java 
Mon Jun 27 22:13:39 2011
@@ -18,16 +18,15 @@ package org.apache.catalina.valves;
 
 import java.io.IOException;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Pattern;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
 
-import org.apache.catalina.LifecycleException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
 import org.apache.juli.logging.Log;
@@ -40,13 +39,16 @@ import org.apache.juli.logging.LogFactor
  * users - regardless of whether or not they provide a session token with their
  * requests.
  */
-public class CrawlerSessionManagerValve extends ValveBase {
+public class CrawlerSessionManagerValve extends ValveBase
+        implements HttpSessionBindingListener {
 
     private static final Log log =
         LogFactory.getLog(CrawlerSessionManagerValve.class);
 
-    private Map<String,SessionInfo> uaIpSessionInfo =
-        new ConcurrentHashMap<String, SessionInfo>();
+    private Map<String,String> clientIpSessionId =
+        new ConcurrentHashMap<String, String>();
+    private Map<String,String> sessionIdClientIp =
+        new ConcurrentHashMap<String, String>();
 
     private String crawlerUserAgents =
         ".*[bB]ot.*|.*Yahoo! Slurp.*|.*Feedfetcher-Google.*";
@@ -106,11 +108,8 @@ public class CrawlerSessionManagerValve 
     }
 
 
-    @Override
-    protected void initInternal() throws LifecycleException {
-        super.initInternal();
-        
-        uaPattern = Pattern.compile(crawlerUserAgents);
+    public Map<String,String> getClientIpSessionId() {
+        return clientIpSessionId;
     }
 
 
@@ -119,7 +118,7 @@ public class CrawlerSessionManagerValve 
             ServletException {
 
         boolean isBot = false;
-        SessionInfo sessionInfo = null;
+        String sessionId = null;
         String clientIp = null;
 
         if (log.isDebugEnabled()) {
@@ -158,12 +157,12 @@ public class CrawlerSessionManagerValve 
             // If this is a bot, is the session ID known?
             if (isBot) {
                 clientIp = request.getRemoteAddr();
-                sessionInfo = uaIpSessionInfo.get(clientIp);
-                if (sessionInfo != null) {
-                    request.setRequestedSessionId(sessionInfo.getSessionId());
+                sessionId = clientIpSessionId.get(clientIp);
+                if (sessionId != null) {
+                    request.setRequestedSessionId(sessionId);
                     if (log.isDebugEnabled()) {
-                        log.debug(request.hashCode() +
-                                ": SessionID=" + sessionInfo.getSessionId());
+                        log.debug(request.hashCode() + ": SessionID=" +
+                                sessionId);
                     }
                 }
             }
@@ -172,11 +171,14 @@ public class CrawlerSessionManagerValve 
         getNext().invoke(request, response);
         
         if (isBot) {
-            if (sessionInfo == null) {
+            if (sessionId == null) {
                 // Has bot just created a session, if so make a note of it
                 HttpSession s = request.getSession(false);
                 if (s != null) {
-                    uaIpSessionInfo.put(clientIp, new SessionInfo(s.getId()));
+                    clientIpSessionId.put(clientIp, s.getId());
+                    sessionIdClientIp.put(s.getId(), clientIp);
+                    // #valueUnbound() will be called on session expiration
+                    s.setAttribute(this.getClass().getName(), this);
                     s.setMaxInactiveInterval(sessionInactiveInterval);
 
                     if (log.isDebugEnabled()) {
@@ -185,12 +187,9 @@ public class CrawlerSessionManagerValve 
                     }
                 }
             } else {
-                sessionInfo.access();
-
                 if (log.isDebugEnabled()) {
                     log.debug(request.hashCode() +
-                            ": Bot session accessed. SessionID=" +
-                            sessionInfo.getSessionId());
+                            ": Bot session accessed. SessionID=" + sessionId);
                 }
             }
         }
@@ -198,44 +197,16 @@ public class CrawlerSessionManagerValve 
 
 
     @Override
-    public void backgroundProcess() {
-        super.backgroundProcess();
-        
-        long expireTime = System.currentTimeMillis() -
-                (sessionInactiveInterval + 60) * 1000;
-
-        Iterator<Entry<String,SessionInfo>> iter =
-            uaIpSessionInfo.entrySet().iterator();
-
-        // Remove any sessions in the cache that have expired. 
-        while (iter.hasNext()) {
-            Entry<String,SessionInfo> entry = iter.next();
-            if (entry.getValue().getLastAccessed() < expireTime) {
-                iter.remove();
-            }
-        }
+    public void valueBound(HttpSessionBindingEvent event) {
+        // NOOP
     }
 
 
-    private static final class SessionInfo {
-        private final String sessionId;
-        private volatile long lastAccessed;
-        
-        public SessionInfo(String sessionId) {
-            this.sessionId = sessionId;
-            this.lastAccessed = System.currentTimeMillis();
-        }
-
-        public String getSessionId() {
-            return sessionId;
-        }
-
-        public long getLastAccessed() {
-            return lastAccessed;
-        }
-
-        public void access() {
-            lastAccessed = System.currentTimeMillis();
+    @Override
+    public void valueUnbound(HttpSessionBindingEvent event) {
+        String clientIp = sessionIdClientIp.remove(event.getSession().getId());
+        if (clientIp != null) {
+            clientIpSessionId.remove(clientIp);
         }
     }
 }

Modified: tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml?rev=1140347&r1=1140346&r2=1140347&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml 
(original)
+++ tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml Mon Jun 
27 22:13:39 2011
@@ -103,6 +103,44 @@
  
   </mbean>
 
+  <mbean name="CrawlerSessionManagerValve"
+         description="Valve that ensures web crawlers always use sessions even 
if no session ID is presented by the client"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.CrawlerSessionManagerValve">
+         
+    <attribute name="asyncSupported"
+               description="Does this valve support async reporting."
+               is="true"
+               type="boolean"/>
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="clientIpSessionId"
+               description="Current Map of client IP address to session ID 
managed by this Valve"
+               type="java.util.Map"
+               writeable="false"/>
+
+    <attribute name="crawlerUserAgents"
+               description="Specify the regular expression used to identify 
crawlers based in the User-Agent header provided."
+               type="java.lang.String"
+               writeable="true"/>
+
+    <attribute name="sessionInactiveInterval"
+               description="Specify the session timeout (in seconds) for a 
crawler's session."
+               type="int"
+               writeable="true"/>
+
+    <attribute name="stateName"
+               description="The name of the LifecycleState that this component 
is currently in"
+               type="java.lang.String"
+               writeable="false"/>
+ 
+  </mbean>
+
   <mbean name="ErrorReportValve"
          description="Implementation of a Valve that outputs HTML error pages"
          domain="Catalina"



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to