Author: remm
Date: Thu Jan 16 22:07:28 2014
New Revision: 1558930

URL: http://svn.apache.org/r1558930
Log:
- Add dedicated listener for framework and EE integration.
- Fix context classloader with SSO session expiration.

Added:
    tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java
Modified:
    tomcat/trunk/java/org/apache/catalina/Context.java
    tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java
    tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java
    tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java
    tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
    tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java
    tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java
    tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/catalina/Context.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Context.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Context.java Thu Jan 16 22:07:28 2014
@@ -1069,6 +1069,18 @@ public interface Context extends Contain
 
 
     /**
+     * Get the associated ThreadBindingListener.
+     */
+    public ThreadBindingListener getThreadBindingListener();
+
+
+    /**
+     * Get the associated ThreadBindingListener.
+     */
+    public void setThreadBindingListener(ThreadBindingListener 
threadBindingListener);
+
+
+    /**
      * Return the set of watched resources for this Context. If none are
      * defined, a zero length array will be returned.
      */

Added: tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java?rev=1558930&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java (added)
+++ tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java Thu Jan 16 
22:07:28 2014
@@ -0,0 +1,29 @@
+/*
+ * 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.catalina;
+
+
+/**
+ * Callback for establishing naming association when entering the application
+ * scope. This corresponds to setting the context classloader.
+ */
+public interface ThreadBindingListener {
+
+    public void bind();
+    public void unbind();
+
+}

Modified: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java Thu 
Jan 16 22:07:28 2014
@@ -20,17 +20,23 @@ package org.apache.catalina.authenticato
 
 
 import java.io.IOException;
+import java.security.AccessController;
 import java.security.Principal;
+import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.Cookie;
 
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Manager;
 import org.apache.catalina.Realm;
 import org.apache.catalina.Session;
 import org.apache.catalina.SessionEvent;
 import org.apache.catalina.SessionListener;
+import org.apache.catalina.ThreadBindingListener;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
 import org.apache.catalina.valves.ValveBase;
@@ -415,7 +421,15 @@ public class SingleSignOn extends ValveB
                 reverse.remove(sessions[i]);
             }
             // Invalidate this session
-            sessions[i].expire();
+            ClassLoader oldContextClassLoader = null;
+            try {
+                oldContextClassLoader = bindThread(sessions[i]);
+                sessions[i].expire();
+            } finally {
+                if (oldContextClassLoader != null) {
+                    unbindThread(sessions[i], oldContextClassLoader);
+                }
+            }
         }
 
         // NOTE:  Clients may still possess the old single sign on cookie,
@@ -424,6 +438,94 @@ public class SingleSignOn extends ValveB
 
     }
 
+    protected ClassLoader bindThread(Session session) {
+
+        Manager manager = session.getManager();
+        Context context = null;
+        ClassLoader contextClassLoader = null;
+        ThreadBindingListener threadBindingListener = null;
+        if (manager != null) {
+            context = manager.getContext();
+        }
+        if (context != null) {
+            if (context.getLoader() != null && 
context.getLoader().getClassLoader() != null) {
+                contextClassLoader = context.getLoader().getClassLoader();
+            }
+            threadBindingListener = context.getThreadBindingListener();
+        }
+        if (threadBindingListener == null || contextClassLoader == null) {
+            return null;
+        }
+
+        if (Globals.IS_SECURITY_ENABLED) {
+            return AccessController.doPrivileged(new 
PrivilegedBind(contextClassLoader, threadBindingListener));
+        } else {
+            ClassLoader oldContextClassLoader =
+                    Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+            threadBindingListener.bind();
+            return oldContextClassLoader;
+        }
+
+    }
+
+    protected class PrivilegedBind implements PrivilegedAction<ClassLoader> {
+        private ClassLoader contextClassLoader;
+        private ThreadBindingListener threadBindingListener;
+
+        PrivilegedBind(ClassLoader contextClassLoader, ThreadBindingListener 
threadBindingListener) {
+            this.contextClassLoader = contextClassLoader;
+            this.threadBindingListener = threadBindingListener;
+        }
+
+        public ClassLoader run() {
+            ClassLoader oldContextClassLoader =
+                    Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+            threadBindingListener.bind();
+            return oldContextClassLoader;
+        }
+    }
+
+    protected void unbindThread(Session session, ClassLoader 
oldContextClassLoader) {
+
+        Manager manager = session.getManager();
+        Context context = null;
+        ThreadBindingListener threadBindingListener = null;
+        if (manager != null) {
+            context = manager.getContext();
+        }
+        if (context != null) {
+            threadBindingListener = context.getThreadBindingListener();
+        }
+        if (threadBindingListener == null) {
+            return;
+        }
+
+        if (Globals.IS_SECURITY_ENABLED) {
+            AccessController.doPrivileged(new 
PrivilegedUnbind(oldContextClassLoader, threadBindingListener));
+        } else {
+            threadBindingListener.unbind();
+            
Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+        }
+
+    }
+
+    protected class PrivilegedUnbind implements PrivilegedAction<Void> {
+        private ClassLoader oldContextClassLoader;
+        private ThreadBindingListener threadBindingListener;
+
+        PrivilegedUnbind(ClassLoader oldContextClassLoader, 
ThreadBindingListener threadBindingListener) {
+            this.oldContextClassLoader = oldContextClassLoader;
+            this.threadBindingListener = threadBindingListener;
+        }
+
+        public Void run() {
+            threadBindingListener.unbind();
+            
Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+            return null;
+        }
+    }
 
     /**
      * Attempts reauthentication to the given <code>Realm</code> using

Modified: tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java Thu 
Jan 16 22:07:28 2014
@@ -670,6 +670,7 @@ final class ApplicationDispatcher implem
 
         if (oldCCL != contextClassLoader) {
             Thread.currentThread().setContextClassLoader(contextClassLoader);
+            context.getThreadBindingListener().bind();
         } else {
             oldCCL = null;
         }
@@ -795,8 +796,10 @@ final class ApplicationDispatcher implem
         }
 
         // Reset the old context class loader
-        if (oldCCL != null)
+        if (oldCCL != null) {
+            context.getThreadBindingListener().unbind();
             Thread.currentThread().setContextClassLoader(oldCCL);
+        }
 
         // Unwrap request/response if needed
         // See Bugzilla 30949

Modified: tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java Thu Jan 16 
22:07:28 2014
@@ -55,6 +55,7 @@ import org.apache.catalina.LifecycleStat
 import org.apache.catalina.Loader;
 import org.apache.catalina.Pipeline;
 import org.apache.catalina.Realm;
+import org.apache.catalina.ThreadBindingListener;
 import org.apache.catalina.Valve;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.connector.Request;
@@ -1354,6 +1355,10 @@ public abstract class ContainerBase exte
                             Thread.currentThread().getContextClassLoader();
                     Thread.currentThread().setContextClassLoader(
                             loader.getClassLoader());
+                    ThreadBindingListener tbl = ((Context) 
container).getThreadBindingListener();
+                    if (tbl != null) {
+                        tbl.bind();
+                    }
                 }
                 container.backgroundProcess();
                 Container[] children = container.findChildren();
@@ -1367,9 +1372,15 @@ public abstract class ContainerBase exte
                 log.error("Exception invoking periodic operation: ", t);
             } finally {
                 if (originalClassLoader != null) {
+                    if (container instanceof Context) {
+                        ThreadBindingListener tbl = ((Context) 
container).getThreadBindingListener();
+                        if (tbl != null) {
+                            tbl.unbind();
+                        }
+                    }
                     Thread.currentThread().setContextClassLoader(
                             originalClassLoader);
-                }
+               }
             }
         }
     }

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Thu Jan 16 
22:07:28 2014
@@ -92,6 +92,7 @@ import org.apache.catalina.Loader;
 import org.apache.catalina.Manager;
 import org.apache.catalina.Pipeline;
 import org.apache.catalina.Realm;
+import org.apache.catalina.ThreadBindingListener;
 import org.apache.catalina.Valve;
 import org.apache.catalina.WebResource;
 import org.apache.catalina.WebResourceRoot;
@@ -807,6 +808,11 @@ public class StandardContext extends Con
 
     private String containerSciFilter;
 
+    protected static final ThreadBindingListener DEFAULT_NAMING_LISTENER = 
(new ThreadBindingListener() {
+        public void bind() {}
+        public void unbind() {}
+    });
+    protected ThreadBindingListener threadBindingListener = 
DEFAULT_NAMING_LISTENER;
 
     // ----------------------------------------------------- Context Properties
 
@@ -2386,6 +2392,17 @@ public class StandardContext extends Con
         this.jspConfigDescriptor = descriptor;
     }
 
+    @Override
+    public ThreadBindingListener getThreadBindingListener() {
+        return threadBindingListener;
+    }
+
+    @Override
+    public void setThreadBindingListener(ThreadBindingListener 
threadBindingListener) {
+        this.threadBindingListener = threadBindingListener;
+    }
+
+
     // ------------------------------------------------------ Public Properties
 
     /**
@@ -5712,6 +5729,9 @@ public class StandardContext extends Con
             Thread.currentThread().setContextClassLoader
                 (getLoader().getClassLoader());
         }
+        if (getThreadBindingListener() != null) {
+            getThreadBindingListener().bind();
+        }
 
         if (isUseNaming()) {
             try {
@@ -5735,6 +5755,9 @@ public class StandardContext extends Con
             ContextBindings.unbindThread(this, this);
         }
 
+        if (getThreadBindingListener() != null) {
+            getThreadBindingListener().unbind();
+        }
         Thread.currentThread().setContextClassLoader(oldContextClassLoader);
     }
 

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java Thu Jan 
16 22:07:28 2014
@@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.catalina.Context;
 import org.apache.catalina.Globals;
+import org.apache.catalina.ThreadBindingListener;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.comet.CometEvent;
 import org.apache.catalina.connector.ClientAbortException;
@@ -130,11 +131,14 @@ final class StandardHostValve extends Va
             // This should eventually move to Engine, it's generic.
             if (Globals.IS_SECURITY_ENABLED) {
                 PrivilegedAction<Void> pa = new PrivilegedSetTccl(
-                        context.getLoader().getClassLoader());
+                        context.getLoader().getClassLoader(), 
+                        context.getThreadBindingListener(),
+                        true);
                 AccessController.doPrivileged(pa);
             } else {
                 Thread.currentThread().setContextClassLoader
                         (context.getLoader().getClassLoader());
+                context.getThreadBindingListener().bind();
             }
         }
         if (request.isAsyncSupported()) {
@@ -201,9 +205,11 @@ final class StandardHostValve extends Va
 
         // Restore the context classloader
         if (Globals.IS_SECURITY_ENABLED) {
-            PrivilegedAction<Void> pa = new PrivilegedSetTccl(MY_CLASSLOADER);
+            PrivilegedAction<Void> pa = new PrivilegedSetTccl(MY_CLASSLOADER, 
+                    context.getThreadBindingListener(), false);
             AccessController.doPrivileged(pa);
         } else {
+            context.getThreadBindingListener().unbind();
             Thread.currentThread().setContextClassLoader(MY_CLASSLOADER);
         }
     }
@@ -232,6 +238,7 @@ final class StandardHostValve extends Va
             // This should eventually move to Engine, it's generic.
             Thread.currentThread().setContextClassLoader
                     (context.getLoader().getClassLoader());
+            context.getThreadBindingListener().bind();
         }
 
         // Ask this Context to process this request
@@ -257,6 +264,7 @@ final class StandardHostValve extends Va
         }
 
         // Restore the context classloader
+        context.getThreadBindingListener().unbind();
         Thread.currentThread().setContextClassLoader
             (StandardHostValve.class.getClassLoader());
 
@@ -508,14 +516,23 @@ final class StandardHostValve extends Va
     private static class PrivilegedSetTccl implements PrivilegedAction<Void> {
 
         private final ClassLoader cl;
+        private final ThreadBindingListener tbl;
+        private final boolean bind;
 
-        PrivilegedSetTccl(ClassLoader cl) {
+        PrivilegedSetTccl(ClassLoader cl, ThreadBindingListener tbl, boolean 
bind) {
             this.cl = cl;
+            this.bind = bind;
+            this.tbl = tbl;
         }
 
         @Override
         public Void run() {
             Thread.currentThread().setContextClassLoader(cl);
+            if (bind) {
+                tbl.bind();
+            } else {
+                tbl.unbind();
+            }
             return null;
         }
     }

Modified: tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java Thu 
Jan 16 22:07:28 2014
@@ -42,6 +42,7 @@ public final class SecurityClassLoad {
             return;
         }
 
+        loadAuthenticatorPackage(loader);
         loadCorePackage(loader);
         loadCoyotePackage(loader);
         loadLoaderPackage(loader);
@@ -55,6 +56,18 @@ public final class SecurityClassLoad {
     }
 
 
+    private static final void loadAuthenticatorPackage(ClassLoader loader)
+            throws Exception {
+        final String basePackage = "org.apache.catalina.authenticator.";
+        loader.loadClass
+            (basePackage +
+             "SingleSignOn$PrivilegedBind");
+        loader.loadClass
+            (basePackage +
+             "SingleSignOn$PrivilegedUnbind");
+   }
+
+
     private static final void loadCorePackage(ClassLoader loader)
             throws Exception {
         final String basePackage = "org.apache.catalina.core.";

Modified: tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java Thu Jan 16 
22:07:28 2014
@@ -43,6 +43,7 @@ import org.apache.catalina.Loader;
 import org.apache.catalina.Manager;
 import org.apache.catalina.Pipeline;
 import org.apache.catalina.Realm;
+import org.apache.catalina.ThreadBindingListener;
 import org.apache.catalina.Valve;
 import org.apache.catalina.WebResourceRoot;
 import org.apache.catalina.Wrapper;
@@ -730,4 +731,11 @@ public class FailedContext extends Lifec
 
     @Override
     public String getContainerSciFilter() { return null; }
+
+    @Override
+    public ThreadBindingListener getThreadBindingListener() { return null; }
+
+    @Override
+    public void setThreadBindingListener(ThreadBindingListener 
threadBindingListener) { /* NO-OP */ }
+
 }
\ No newline at end of file

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1558930&r1=1558929&r2=1558930&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Jan 16 22:07:28 2014
@@ -196,6 +196,9 @@
         grouped more logically in JConsole. Generally, components are now
         grouped by Host and then by Context. (markt)
       </fix>
+      <add>
+        Context listener to allow better EE and framework integration. (remm)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Coyote">



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

Reply via email to