FELIX-4841 : Support HttpSessionIdListener. Initial work tracking the listener

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1670864 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
new file mode 100644
index 0000000..eeb671a
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
@@ -0,0 +1,36 @@
+/*
+ * 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.felix.http.base.internal.runtime;
+
+import javax.servlet.http.HttpSessionIdListener;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Info object for registered http session id listeners
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class HttpSessionIdListenerInfo extends ListenerInfo<HttpSessionIdListener>
+{
+    public HttpSessionIdListenerInfo(final ServiceReference<HttpSessionIdListener> ref)
+    {
+        super(ref);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java
index 979423a..d7411dd 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java
@@ -24,6 +24,7 @@
 import javax.annotation.Nonnull;
 
 import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
@@ -97,6 +98,18 @@
         getRegistryForContext(contextHandler).removeListener(info);
     }
 
+    void addListener(@Nonnull final HttpSessionIdListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).addListener(info);
+    }
+
+    void removeListener(@Nonnull final HttpSessionIdListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).removeListener(info);
+    }
+
     void addListener(@Nonnull final HttpSessionListenerInfo info,
             final ContextHandler contextHandler)
     {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
index 19244a3..30dcdc1 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
@@ -34,9 +34,11 @@
 import javax.servlet.http.HttpSessionAttributeListener;
 import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionIdListener;
 import javax.servlet.http.HttpSessionListener;
 
 import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
@@ -65,6 +67,9 @@
     /** Session listeners. */
     private final Map<ServiceReference<HttpSessionListener>, HttpSessionListener> sessionListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionListener>, HttpSessionListener>();
 
+    /** Session id listeners. */
+    private final Map<ServiceReference<HttpSessionIdListener>, HttpSessionIdListener> sessionIdListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionIdListener>, HttpSessionIdListener>();
+
     /** Request listeners. */
     private final Map<ServiceReference<ServletRequestListener>, ServletRequestListener> requestListeners = new ConcurrentSkipListMap<ServiceReference<ServletRequestListener>, ServletRequestListener>();
 
@@ -204,6 +209,35 @@
     }
 
     /**
+     * Add session id listener
+     *
+     * @param info
+     */
+    void addListener(@Nonnull final HttpSessionIdListenerInfo info)
+    {
+        final HttpSessionIdListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.sessionIdListeners.put(info.getServiceReference(),
+                    service);
+        }
+    }
+
+    /**
+     * Remove session id listener
+     *
+     * @param info
+     */
+    void removeListener(@Nonnull final HttpSessionIdListenerInfo info)
+    {
+        final HttpSessionIdListener service = this.sessionIdListeners.remove(info.getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    /**
      * Add request listener
      *
      * @param info
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 84da0b9..7b74a4a 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
@@ -43,6 +43,7 @@
 import org.apache.felix.http.base.internal.runtime.AbstractInfo;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
@@ -372,20 +373,23 @@
                 {
                     final List<ContextHandler> handlerList = this.getMatchingContexts(info);
                     this.servicesMap.put(info, handlerList);
-                    for(final ContextHandler h : handlerList)
-                    {
-                        this.registerWhiteboardService(h, info);
-                    }
                     if (handlerList.isEmpty())
                     {
                         this.serviceFailures.put(info, FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
                     }
+                    else
+                    {
+                        for(final ContextHandler h : handlerList)
+                        {
+                            this.registerWhiteboardService(h, info);
+                        }
+                    }
                 }
             }
             else
             {
                 final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
-                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
+                SystemLogger.debug("Ignoring invalid " + type + " service " + info.getServiceReference());
                 this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
             }
         }
@@ -419,7 +423,7 @@
 
     /**
      * Register whiteboard service in the http service
-     * @param contextInfo Context info
+     * @param handler Context handler
      * @param info Whiteboard service info
      */
     private void registerWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
@@ -451,6 +455,10 @@
             {
                 this.listenerRegistry.addListener((HttpSessionAttributeListenerInfo) info, handler);
             }
+            else if ( info instanceof HttpSessionIdListenerInfo )
+            {
+                this.listenerRegistry.addListener((HttpSessionIdListenerInfo) info, handler);
+            }
             else if ( info instanceof ServletRequestListenerInfo )
             {
                 this.listenerRegistry.addListener((ServletRequestListenerInfo) info, handler);
@@ -460,21 +468,21 @@
                 this.listenerRegistry.addListener((ServletRequestAttributeListenerInfo) info, handler);
             }
         }
-        catch (RegistrationFailureException e)
+        catch (final RegistrationFailureException e)
         {
             serviceFailures.put(e.getInfo(), e.getErrorCode());
-            SystemLogger.error("Exception while adding servlet", e);
+            SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
         }
-        catch (RuntimeException e)
+        catch (final RuntimeException e)
         {
             serviceFailures.put(info, FAILURE_REASON_UNKNOWN);
-            throw e;
+            SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
         }
     }
 
     /**
      * Unregister whiteboard service from the http service
-     * @param contextInfo Context info
+     * @param handler Context handler
      * @param info Whiteboard service info
      */
     private void unregisterWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
@@ -506,6 +514,10 @@
             {
                 this.listenerRegistry.removeListener((HttpSessionAttributeListenerInfo) info, handler);
             }
+            else if ( info instanceof HttpSessionIdListenerInfo )
+            {
+                this.listenerRegistry.removeListener((HttpSessionIdListenerInfo) info, handler);
+            }
             else if ( info instanceof ServletRequestListenerInfo )
             {
                 this.listenerRegistry.removeListener((ServletRequestListenerInfo) info, handler);
@@ -515,7 +527,7 @@
                 this.listenerRegistry.removeListener((ServletRequestAttributeListenerInfo) info, handler);
             }
         }
-        catch (RegistrationFailureException e)
+        catch (final RegistrationFailureException e)
         {
             serviceFailures.put(e.getInfo(), e.getErrorCode());
             SystemLogger.error("Exception while removing servlet", e);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java
new file mode 100644
index 0000000..5ed3170
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java
@@ -0,0 +1,57 @@
+/*
+ * 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.felix.http.base.internal.whiteboard.tracker;
+
+import javax.servlet.http.HttpSessionIdListener;
+
+import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
+import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
+import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+
+public final class HttpSessionIdListenerTracker extends AbstractReferenceTracker<HttpSessionIdListener>
+{
+
+    private static org.osgi.framework.Filter createFilter(final BundleContext btx)
+    {
+        try
+        {
+            return btx.createFilter(String.format("(&(objectClass=%s)(%s=*)(!(%s~=false)))",
+                    HttpSessionIdListener.class.getName(),
+                    HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER,
+                    HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER));
+        }
+        catch ( final InvalidSyntaxException ise)
+        {
+            // we can safely ignore it as the above filter is a constant
+        }
+        return null; // we never get here - and if we get an NPE which is fine
+    }
+
+    public HttpSessionIdListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    {
+        super(manager, context, createFilter(context));
+    }
+
+    @Override
+    protected WhiteboardServiceInfo<HttpSessionIdListener> getServiceInfo(final ServiceReference<HttpSessionIdListener> ref) {
+        return new HttpSessionIdListenerInfo(ref);
+    }
+}