FELIX-4781 : Implement various listeners

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1659618 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
index ef9f9a0..95e0743 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
@@ -19,6 +19,8 @@
 import java.io.IOException;
 
 import javax.servlet.ServletContext;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSessionAttributeListener;
@@ -31,4 +33,8 @@
     HttpSessionAttributeListener getHttpSessionAttributeListener();
 
     HttpSessionListener getHttpSessionListener();
+
+    ServletRequestListener getServletRequestListener();
+
+    ServletRequestAttributeListener getServletRequestAttributeListener();
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ServletContextImpl.java
index 23b1a24..2f8d866 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ServletContextImpl.java
@@ -36,6 +36,8 @@
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
 import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
 import javax.servlet.descriptor.JspConfigDescriptor;
@@ -394,6 +396,18 @@
     }
 
     @Override
+    public ServletRequestListener getServletRequestListener()
+    {
+        return null;
+    }
+
+    @Override
+    public ServletRequestAttributeListener getServletRequestAttributeListener()
+    {
+        return null;
+    }
+
+    @Override
     public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException
     {
         return this.httpContext.handleSecurity(req, res);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
index c657215..b322bdc 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
@@ -40,6 +40,8 @@
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestEvent;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
@@ -475,6 +477,41 @@
         }
 
         @Override
+        public void setAttribute(final String name, final Object value)
+        {
+            if ( value == null )
+            {
+                this.removeAttribute(name);
+            }
+            final Object oldValue = this.getAttribute(name);
+            super.setAttribute(name, value);
+            if ( this.servletContext.getServletRequestAttributeListener() != null )
+            {
+                if ( oldValue == null )
+                {
+                    this.servletContext.getServletRequestAttributeListener().attributeAdded(new ServletRequestAttributeEvent(this.servletContext, this, name, value));
+                }
+                else
+                {
+                    this.servletContext.getServletRequestAttributeListener().attributeReplaced(new ServletRequestAttributeEvent(this.servletContext, this, name, oldValue));
+                }
+            }
+        }
+
+        @Override
+        public void removeAttribute(final String name) {
+            final Object oldValue = this.getAttribute(name);
+            if ( oldValue != null )
+            {
+                super.removeAttribute(name);
+                if ( this.servletContext.getServletRequestAttributeListener() != null )
+                {
+                    this.servletContext.getServletRequestAttributeListener().attributeRemoved(new ServletRequestAttributeEvent(this.servletContext, this, name, oldValue));
+                }
+            }
+        }
+
+        @Override
         public String toString()
         {
             return getClass().getSimpleName() + "->" + super.getRequest();
@@ -574,10 +611,15 @@
         ExtServletContext servletContext = (servletHandler != null) ? servletHandler.getContext() : null;
         RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
 
+        final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, servletHandler.getContextServiceId());
+        final FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, req.getDispatcherType(), requestURI);
+
         try
         {
-            final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, servletHandler.getContextServiceId());
-            final FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, req.getDispatcherType(), requestURI);
+            if ( servletContext.getServletRequestListener() != null )
+            {
+                servletContext.getServletRequestListener().requestInitialized(new ServletRequestEvent(servletContext, wrappedRequest));
+            }
             invokeChain(filterHandlers, servletHandler, wrappedRequest, wrappedResponse);
         }
         catch ( final Exception e)
@@ -587,6 +629,13 @@
 
             wrappedResponse.sendError(500);
         }
+        finally
+        {
+            if ( servletContext.getServletRequestListener() != null )
+            {
+                servletContext.getServletRequestListener().requestDestroyed(new ServletRequestEvent(servletContext, wrappedRequest));
+            }
+        }
     }
 
     @Override
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
index 346c53c..3926bae 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
@@ -393,6 +393,12 @@
     public void setAttribute(final String name, final Object value)
     {
         this.checkInvalid();
+        if ( value == null )
+        {
+            this.removeAttribute(name);
+            return;
+        }
+
         final Object oldValue = this.getAttribute(name);
         // wrap http session binding listener to avoid container calling it!
         if ( this.keyPrefix != null && value instanceof HttpSessionBindingListener )
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
index af5bc80..f89186f 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
@@ -26,6 +26,10 @@
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
 import javax.servlet.http.HttpSessionAttributeListener;
 import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionEvent;
@@ -37,6 +41,8 @@
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceObjects;
 import org.osgi.framework.ServiceReference;
@@ -68,6 +74,14 @@
     private final Map<ServiceReference<HttpSessionListener>, HttpSessionListener> sessionListeners =
             new ConcurrentSkipListMap<ServiceReference<HttpSessionListener>, HttpSessionListener>();
 
+    /** Request listeners. */
+    private final Map<ServiceReference<ServletRequestListener>, ServletRequestListener> requestListeners =
+            new ConcurrentSkipListMap<ServiceReference<ServletRequestListener>, ServletRequestListener>();
+
+    /** Request attribute listeners. */
+    private final Map<ServiceReference<ServletRequestAttributeListener>, ServletRequestAttributeListener> requestAttributeListeners =
+            new ConcurrentSkipListMap<ServiceReference<ServletRequestAttributeListener>, ServletRequestAttributeListener>();
+
     /** The http bundle. */
     private final Bundle bundle;
 
@@ -168,7 +182,9 @@
                             this.sharedContext,
                             holder.servletContextHelper,
                             this.getSessionListener(),
-                            this.getSessionAttributeListener());
+                            this.getSessionAttributeListener(),
+                            this.getServletRequestListener(),
+                            this.getServletRequestAttributeListener());
                     this.contextMap.put(key, holder);
                 }
             }
@@ -299,6 +315,72 @@
         }
     }
 
+    /**
+     * Add request listener
+     * @param info
+     */
+    public void addListener(@Nonnull final ServletRequestListenerInfo info)
+    {
+        final ServiceObjects<ServletRequestListener> so =  bundle.getBundleContext().getServiceObjects(info.getServiceReference());
+        if ( so != null )
+        {
+            final  ServletRequestListener service = bundle.getBundleContext().getServiceObjects(info.getServiceReference()).getService();
+            if ( service != null )
+            {
+                this.requestListeners.put(info.getServiceReference(), service);
+            }
+        }
+    }
+
+    /**
+     * Remove request listener
+     * @param info
+     */
+    public void removeListener(@Nonnull final ServletRequestListenerInfo info)
+    {
+        final ServletRequestListener service = this.requestListeners.remove(info.getServiceReference());
+        if ( service != null )
+        {
+            final ServiceObjects<ServletRequestListener> so =  bundle.getBundleContext().getServiceObjects(info.getServiceReference());
+            if ( so != null ) {
+                so.ungetService(service);
+            }
+        }
+    }
+
+    /**
+     * Add request attribute listener
+     * @param info
+     */
+    public void addListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+    {
+        final ServiceObjects<ServletRequestAttributeListener> so =  bundle.getBundleContext().getServiceObjects(info.getServiceReference());
+        if ( so != null )
+        {
+            final  ServletRequestAttributeListener service = bundle.getBundleContext().getServiceObjects(info.getServiceReference()).getService();
+            if ( service != null )
+            {
+                this.requestAttributeListeners.put(info.getServiceReference(), service);
+            }
+        }
+    }
+
+    /**
+     * Remove request attribute listener
+     * @param info
+     */
+    public void removeListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+    {
+        final ServletRequestAttributeListener service = this.requestAttributeListeners.remove(info.getServiceReference());
+        if ( service != null )
+        {
+            final ServiceObjects<ServletRequestAttributeListener> so =  bundle.getBundleContext().getServiceObjects(info.getServiceReference());
+            if ( so != null ) {
+                so.ungetService(service);
+            }
+        }
+    }
+
     private static final class ContextHolder
     {
         public long counter;
@@ -387,4 +469,56 @@
             }
         };
     }
+
+    private ServletRequestListener getServletRequestListener()
+    {
+        return new ServletRequestListener() {
+
+            @Override
+            public void requestDestroyed(final ServletRequestEvent sre) {
+                for(final ServletRequestListener l : requestListeners.values())
+                {
+                    l.requestDestroyed(sre);
+                }
+            }
+
+            @Override
+            public void requestInitialized(final ServletRequestEvent sre) {
+                for(final ServletRequestListener l : requestListeners.values())
+                {
+                    l.requestInitialized(sre);
+                }
+            }
+        };
+    }
+
+    private ServletRequestAttributeListener getServletRequestAttributeListener()
+    {
+        return new ServletRequestAttributeListener() {
+
+            @Override
+            public void attributeAdded(final ServletRequestAttributeEvent srae) {
+                for(final ServletRequestAttributeListener l : requestAttributeListeners.values())
+                {
+                    l.attributeAdded(srae);
+                }
+            }
+
+            @Override
+            public void attributeRemoved(final ServletRequestAttributeEvent srae) {
+                for(final ServletRequestAttributeListener l : requestAttributeListeners.values())
+                {
+                    l.attributeRemoved(srae);
+                }
+            }
+
+            @Override
+            public void attributeReplaced(final ServletRequestAttributeEvent srae) {
+                for(final ServletRequestAttributeListener l : requestAttributeListeners.values())
+                {
+                    l.attributeReplaced(srae);
+                }
+            }
+        };
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
index e64db90..c152ce7 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
@@ -32,6 +32,8 @@
 import javax.servlet.ServletException;
 import javax.servlet.ServletRegistration;
 import javax.servlet.ServletRegistration.Dynamic;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
 import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
 import javax.servlet.descriptor.JspConfigDescriptor;
@@ -58,18 +60,24 @@
     private final ServletContextHelper contextHelper;
     private final HttpSessionListener sessionListener;
     private final HttpSessionAttributeListener sessionAttributeListener;
+    private final ServletRequestListener requestListener;
+    private final ServletRequestAttributeListener requestAttributeListener;
 
     public PerBundleServletContextImpl(final Bundle bundle,
             final ServletContext sharedContext,
             final ServletContextHelper delegatee,
             final HttpSessionListener sessionListener,
-            final HttpSessionAttributeListener sessionAttributeListener)
+            final HttpSessionAttributeListener sessionAttributeListener,
+            final ServletRequestListener requestListener,
+            final ServletRequestAttributeListener requestAttributeListener)
     {
         this.bundle = bundle;
         this.delegatee = sharedContext;
         this.contextHelper = delegatee;
         this.sessionListener = sessionListener;
         this.sessionAttributeListener = sessionAttributeListener;
+        this.requestListener = requestListener;
+        this.requestAttributeListener = requestAttributeListener;
     }
 
     @Override
@@ -93,6 +101,18 @@
     }
 
     @Override
+    public ServletRequestListener getServletRequestListener()
+    {
+        return this.requestListener;
+    }
+
+    @Override
+    public ServletRequestAttributeListener getServletRequestAttributeListener()
+    {
+        return this.requestAttributeListener;
+    }
+
+    @Override
     public ClassLoader getClassLoader()
     {
         return this.bundle.adapt(BundleWiring.class).getClassLoader();
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
index 2319dfe..7ea4967 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
@@ -40,6 +40,8 @@
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
 import org.apache.felix.http.base.internal.util.MimeTypes;
 import org.osgi.framework.Bundle;
@@ -393,6 +395,14 @@
         {
             handler.addListener((HttpSessionListenerInfo)info );
         }
+        else if ( info instanceof ServletRequestListenerInfo )
+        {
+            handler.addListener((ServletRequestListenerInfo)info );
+        }
+        else if ( info instanceof ServletRequestAttributeListenerInfo )
+        {
+            handler.addListener((ServletRequestAttributeListenerInfo)info );
+        }
     }
 
     /**
@@ -426,6 +436,14 @@
         {
             handler.removeListener((HttpSessionListenerInfo)info );
         }
+        else if ( info instanceof ServletRequestListenerInfo )
+        {
+            handler.removeListener((ServletRequestListenerInfo)info );
+        }
+        else if ( info instanceof ServletRequestAttributeListenerInfo )
+        {
+            handler.removeListener((ServletRequestAttributeListenerInfo)info );
+        }
     }
 
     /**