FELIX-4421 - Upgrade to Jetty 8:

- bumped the embedded Jetty version to latest Jetty 8 version;
- bumped minor versions of all bundles to indicate that this
  version no longer is compatible with Java 5;
- added simple integration test to verify the basic functionality
  provided by the HTTP service.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1565705 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/api/pom.xml b/http/api/pom.xml
index 713536c..50e6297 100644
--- a/http/api/pom.xml
+++ b/http/api/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Api</name>
     <artifactId>org.apache.felix.http.api</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -56,7 +56,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/base/pom.xml b/http/base/pom.xml
index a9c8c72..b15c98b 100644
--- a/http/base/pom.xml
+++ b/http/base/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Base</name>
     <artifactId>org.apache.felix.http.base</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -59,7 +59,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
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 3c9ea01..ca6d952 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
@@ -21,17 +21,24 @@
 import java.net.URL;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.EventListener;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -40,8 +47,8 @@
 import org.osgi.framework.Bundle;
 import org.osgi.service.http.HttpContext;
 
-public final class ServletContextImpl
-    implements ExtServletContext
+@SuppressWarnings("deprecation")
+public final class ServletContextImpl implements ExtServletContext
 {
     private final Bundle bundle;
     private final ServletContext context;
@@ -49,8 +56,7 @@
     private final Map<String, Object> attributes;
     private final ServletContextAttributeListener attributeListener;
 
-    public ServletContextImpl(Bundle bundle, ServletContext context, HttpContext httpContext,
-        ServletContextAttributeListener attributeListener, boolean sharedAttributes)
+    public ServletContextImpl(Bundle bundle, ServletContext context, HttpContext httpContext, ServletContextAttributeListener attributeListener, boolean sharedAttributes)
     {
         this.bundle = bundle;
         this.context = context;
@@ -59,9 +65,84 @@
         this.attributes = sharedAttributes ? null : new ConcurrentHashMap<String, Object>();
     }
 
-    public String getContextPath()
+    public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> type)
     {
-        return this.context.getContextPath();
+        throw new UnsupportedOperationException();
+    }
+
+    public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public FilterRegistration.Dynamic addFilter(String filterName, String className)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addListener(Class<? extends EventListener> type)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addListener(String className)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public <T extends EventListener> void addListener(T listener)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> type)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public ServletRegistration.Dynamic addServlet(String servletName, String className)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public <T extends Filter> T createFilter(Class<T> type) throws ServletException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public <T extends EventListener> T createListener(Class<T> type) throws ServletException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public <T extends Servlet> T createServlet(Class<T> type) throws ServletException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void declareRoles(String... roleNames)
+    {
+        this.context.declareRoles(roleNames);
+    }
+
+    public Object getAttribute(String name)
+    {
+        return (this.attributes != null) ? this.attributes.get(name) : this.context.getAttribute(name);
+    }
+
+    public Enumeration getAttributeNames()
+    {
+        return (this.attributes != null) ? Collections.enumeration(this.attributes.keySet()) : this.context.getAttributeNames();
+    }
+
+    public ClassLoader getClassLoader()
+    {
+        return bundle.getClass().getClassLoader();
     }
 
     public ServletContext getContext(String uri)
@@ -69,29 +150,94 @@
         return this.context.getContext(uri);
     }
 
+    public String getContextPath()
+    {
+        return this.context.getContextPath();
+    }
+
+    public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
+    {
+        return this.context.getDefaultSessionTrackingModes();
+    }
+
+    public int getEffectiveMajorVersion()
+    {
+        return this.context.getEffectiveMajorVersion();
+    }
+
+    public int getEffectiveMinorVersion()
+    {
+        return this.context.getEffectiveMinorVersion();
+    }
+
+    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
+    {
+        return this.context.getEffectiveSessionTrackingModes();
+    }
+
+    public FilterRegistration getFilterRegistration(String filterName)
+    {
+        return this.context.getFilterRegistration(filterName);
+    }
+
+    public Map<String, ? extends FilterRegistration> getFilterRegistrations()
+    {
+        return this.context.getFilterRegistrations();
+    }
+
+    public String getInitParameter(String name)
+    {
+        return this.context.getInitParameter(name);
+    }
+
+    public Enumeration getInitParameterNames()
+    {
+        return this.context.getInitParameterNames();
+    }
+
+    public JspConfigDescriptor getJspConfigDescriptor()
+    {
+        throw new UnsupportedOperationException();
+    }
+
     public int getMajorVersion()
     {
         return this.context.getMajorVersion();
     }
 
+    public String getMimeType(String file)
+    {
+        String type = this.httpContext.getMimeType(file);
+        if (type != null)
+        {
+            return type;
+        }
+
+        return MimeTypes.get().getByFile(file);
+    }
+
     public int getMinorVersion()
     {
         return this.context.getMinorVersion();
     }
 
-    public Set getResourcePaths(String path)
+    public RequestDispatcher getNamedDispatcher(String name)
     {
-        Enumeration paths = this.bundle.getEntryPaths(normalizePath(path));
-        if ((paths == null) || !paths.hasMoreElements()) {
+        return this.context.getNamedDispatcher(name);
+    }
+
+    public String getRealPath(String name)
+    {
+        URL url = getResource(normalizePath(name));
+        if (url == null) {
             return null;
         }
+        return url.toExternalForm();
+    }
 
-        Set<String> set = new HashSet<String>();
-        while (paths.hasMoreElements()) {
-            set.add((String) paths.nextElement());
-        }
-
-        return set;
+    public RequestDispatcher getRequestDispatcher(String uri)
+    {
+        return this.context.getRequestDispatcher(uri);
     }
 
     public URL getResource(String path)
@@ -102,61 +248,114 @@
     public InputStream getResourceAsStream(String path)
     {
         URL res = getResource(path);
-        if (res != null) {
-            try {
+        if (res != null)
+        {
+            try
+            {
                 return res.openStream();
             }
-            catch (IOException e) {
+            catch (IOException e)
+            {
                 // Do nothing
             }
         }
-
         return null;
     }
 
-    private String normalizePath(String path)
+    public Set getResourcePaths(String path)
     {
-        if (path == null) {
+        Enumeration paths = this.bundle.getEntryPaths(normalizePath(path));
+        if ((paths == null) || !paths.hasMoreElements())
+        {
             return null;
         }
 
-        String normalizedPath = path.trim().replaceAll("/+", "/");
-        if (normalizedPath.startsWith("/") && (normalizedPath.length() > 1)) {
-            normalizedPath = normalizedPath.substring(1);
+        Set<String> set = new HashSet<String>();
+        while (paths.hasMoreElements())
+        {
+            set.add((String) paths.nextElement());
         }
 
-        return normalizedPath;
+        return set;
     }
 
-    public RequestDispatcher getRequestDispatcher(String uri)
+    public String getServerInfo()
     {
-        return null;
+        return this.context.getServerInfo();
     }
 
-    public RequestDispatcher getNamedDispatcher(String name)
+    public Servlet getServlet(String name) throws ServletException
     {
-        return null;
+        return this.context.getServlet(name);
     }
 
-    public String getInitParameter(String name)
+    public String getServletContextName()
     {
-        return null;
+        return this.context.getServletContextName();
     }
 
-    public Enumeration getInitParameterNames()
+    public Enumeration getServletNames()
     {
-        return Collections.enumeration(Collections.emptyList());
+        return this.context.getServletNames();
     }
 
-    public Object getAttribute(String name)
+    public ServletRegistration getServletRegistration(String servletName)
     {
-        return (this.attributes != null) ? this.attributes.get(name) : this.context.getAttribute(name);
+        return this.context.getServletRegistration(servletName);
     }
 
-    public Enumeration getAttributeNames()
+    public Map<String, ? extends ServletRegistration> getServletRegistrations()
     {
-        return (this.attributes != null) ? Collections.enumeration(this.attributes.keySet()) : this.context
-            .getAttributeNames();
+        return this.context.getServletRegistrations();
+    }
+
+    public Enumeration getServlets()
+    {
+        return this.context.getServlets();
+    }
+
+    public SessionCookieConfig getSessionCookieConfig()
+    {
+        return this.context.getSessionCookieConfig();
+    }
+
+    public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException
+    {
+        return this.httpContext.handleSecurity(req, res);
+    }
+
+    public void log(Exception cause, String message)
+    {
+        SystemLogger.error(message, cause);
+    }
+
+    public void log(String message)
+    {
+        SystemLogger.info(message);
+    }
+
+    public void log(String message, Throwable cause)
+    {
+        SystemLogger.error(message, cause);
+    }
+
+    public void removeAttribute(String name)
+    {
+        Object oldValue;
+        if (this.attributes != null)
+        {
+            oldValue = this.attributes.remove(name);
+        }
+        else
+        {
+            oldValue = this.context.getAttribute(name);
+            this.context.removeAttribute(name);
+        }
+
+        if (oldValue != null)
+        {
+            attributeListener.attributeRemoved(new ServletContextAttributeEvent(this, name, oldValue));
+        }
     }
 
     public void setAttribute(String name, Object value)
@@ -189,84 +388,29 @@
         }
     }
 
-    public void removeAttribute(String name)
+    public boolean setInitParameter(String name, String value)
     {
-        Object oldValue;
-        if (this.attributes != null)
+        return this.context.setInitParameter(name, value);
+    }
+
+    public void setSessionTrackingModes(Set<SessionTrackingMode> modes)
+    {
+        this.context.setSessionTrackingModes(modes);
+    }
+
+    private String normalizePath(String path)
+    {
+        if (path == null)
         {
-            oldValue = this.attributes.remove(name);
+            return null;
         }
-        else
+
+        String normalizedPath = path.trim().replaceAll("/+", "/");
+        if (normalizedPath.startsWith("/") && (normalizedPath.length() > 1))
         {
-            oldValue = this.context.getAttribute(name);
-            this.context.removeAttribute(name);
+            normalizedPath = normalizedPath.substring(1);
         }
 
-        if (oldValue != null)
-        {
-            attributeListener.attributeRemoved(new ServletContextAttributeEvent(this, name, oldValue));
-        }
-    }
-
-    public Servlet getServlet(String name)
-        throws ServletException
-    {
-        return null;
-    }
-
-    public Enumeration getServlets()
-    {
-        return Collections.enumeration(Collections.emptyList());
-    }
-
-    public Enumeration getServletNames()
-    {
-        return Collections.enumeration(Collections.emptyList());
-    }
-
-    public void log(String message)
-    {
-        SystemLogger.info(message);
-    }
-
-    public void log(Exception cause, String message)
-    {
-        SystemLogger.error(message, cause);
-    }
-
-    public void log(String message, Throwable cause)
-    {
-        SystemLogger.error(message, cause);
-    }
-
-    public String getServletContextName()
-    {
-        return this.context.getServletContextName();
-    }
-
-    public String getRealPath(String name)
-    {
-        return null;
-    }
-
-    public String getServerInfo()
-    {
-        return this.context.getServerInfo();
-    }
-
-    public String getMimeType(String file)
-    {
-        String type = this.httpContext.getMimeType(file);
-        if (type != null) {
-            return type;
-        }
-
-        return MimeTypes.get().getByFile(file);
-    }
-
-    public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res)
-        throws IOException
-    {
-        return this.httpContext.handleSecurity(req, res);
+        return normalizedPath;
     }
 }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
index eb8ff65..c82b336 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
@@ -16,26 +16,369 @@
  */
 package org.apache.felix.http.base.internal.context;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.Assert;
-import org.mockito.Mockito;
-import org.osgi.framework.Bundle;
-import org.osgi.service.http.HttpContext;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletContextAttributeListener;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.*;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpContext;
 
 public class ServletContextImplTest
 {
+    private static class AttributeListener implements ServletContextAttributeListener
+    {
+
+        private int type;
+
+        private String name;
+
+        private Object value;
+
+        public void attributeAdded(ServletContextAttributeEvent scab)
+        {
+            setData(1, scab);
+        }
+
+        public void attributeRemoved(ServletContextAttributeEvent scab)
+        {
+            setData(2, scab);
+        }
+
+        public void attributeReplaced(ServletContextAttributeEvent scab)
+        {
+            setData(3, scab);
+        }
+
+        void checkAdded(String name, Object value)
+        {
+            check(1, name, value);
+        }
+
+        void checkNull()
+        {
+            check(0, null, null);
+        }
+
+        void checkRemoved(String name, Object value)
+        {
+            check(2, name, value);
+        }
+
+        void checkReplaced(String name, Object value)
+        {
+            check(3, name, value);
+        }
+
+        private void check(int type, String name, Object value)
+        {
+            try
+            {
+                Assert.assertEquals(type, this.type);
+                Assert.assertEquals(name, this.name);
+                Assert.assertEquals(value, this.value);
+            }
+            finally
+            {
+                this.type = 0;
+                this.name = null;
+                this.value = null;
+            }
+        }
+
+        private void setData(int type, ServletContextAttributeEvent scab)
+        {
+            this.type = type;
+            this.name = scab.getName();
+            this.value = scab.getValue();
+        }
+    }
+    private class MockServletContext implements ServletContext
+    {
+
+        private Dictionary attributes = new Hashtable();
+
+        public FilterRegistration.Dynamic addFilter(String name, Class<? extends Filter> type)
+        {
+            return null;
+        }
+
+        public FilterRegistration.Dynamic addFilter(String name, Filter filter)
+        {
+            return null;
+        }
+
+        public FilterRegistration.Dynamic addFilter(String name, String className)
+        {
+            return null;
+        }
+
+        public void addListener(Class<? extends EventListener> listener)
+        {
+        }
+
+        public void addListener(String className)
+        {
+        }
+
+        public <T extends EventListener> void addListener(T listener)
+        {
+        }
+
+        public ServletRegistration.Dynamic addServlet(String name, Class<? extends Servlet> type)
+        {
+            return null;
+        }
+
+        public ServletRegistration.Dynamic addServlet(String name, Servlet servlet)
+        {
+            return null;
+        }
+
+        public ServletRegistration.Dynamic addServlet(String name, String className)
+        {
+            return null;
+        }
+
+        public <T extends Filter> T createFilter(Class<T> type) throws ServletException
+        {
+            return null;
+        }
+
+        public <T extends EventListener> T createListener(Class<T> type) throws ServletException
+        {
+            return null;
+        }
+
+        public <T extends Servlet> T createServlet(Class<T> type) throws ServletException
+        {
+            return null;
+        }
+
+        public void declareRoles(String... roleNames)
+        {
+        }
+
+        public Object getAttribute(String name)
+        {
+            return attributes.get(name);
+        }
+
+        public Enumeration getAttributeNames()
+        {
+            return attributes.keys();
+        }
+
+        public ClassLoader getClassLoader()
+        {
+            return ServletContextImplTest.class.getClassLoader();
+        }
+
+        public ServletContext getContext(String uripath)
+        {
+            return null;
+        }
+
+        public String getContextPath()
+        {
+            return null;
+        }
+
+        public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
+        {
+            return null;
+        }
+
+        public int getEffectiveMajorVersion()
+        {
+            return 0;
+        }
+
+        public int getEffectiveMinorVersion()
+        {
+            return 0;
+        }
+
+        public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
+        {
+            return null;
+        }
+
+        public FilterRegistration getFilterRegistration(String name)
+        {
+            return null;
+        }
+
+        public Map<String, ? extends FilterRegistration> getFilterRegistrations()
+        {
+            return null;
+        }
+
+        public String getInitParameter(String name)
+        {
+            return null;
+        }
+
+        public Enumeration getInitParameterNames()
+        {
+            return Collections.enumeration(Collections.emptyList());
+        }
+
+        public JspConfigDescriptor getJspConfigDescriptor()
+        {
+            return null;
+        }
+
+        public int getMajorVersion()
+        {
+            return 0;
+        }
+
+        public String getMimeType(String file)
+        {
+            return null;
+        }
+
+        public int getMinorVersion()
+        {
+            return 0;
+        }
+
+        public RequestDispatcher getNamedDispatcher(String name)
+        {
+            return null;
+        }
+
+        public String getRealPath(String path)
+        {
+            return null;
+        }
+
+        public RequestDispatcher getRequestDispatcher(String path)
+        {
+            return null;
+        }
+
+        public URL getResource(String path)
+        {
+            return null;
+        }
+
+        public InputStream getResourceAsStream(String path)
+        {
+            return null;
+        }
+
+        public Set getResourcePaths(String path)
+        {
+            return null;
+        }
+
+        public String getServerInfo()
+        {
+            return null;
+        }
+
+        public Servlet getServlet(String name)
+        {
+            return null;
+        }
+
+        public String getServletContextName()
+        {
+            return null;
+        }
+
+        public Enumeration getServletNames()
+        {
+            return Collections.enumeration(Collections.emptyList());
+        }
+
+        public ServletRegistration getServletRegistration(String name)
+        {
+            return null;
+        }
+
+        public Map<String, ? extends ServletRegistration> getServletRegistrations()
+        {
+            return null;
+        }
+
+        public Enumeration getServlets()
+        {
+            return Collections.enumeration(Collections.emptyList());
+        }
+
+        public SessionCookieConfig getSessionCookieConfig()
+        {
+            return null;
+        }
+
+        public void log(Exception exception, String msg)
+        {
+        }
+
+        public void log(String msg)
+        {
+        }
+
+        public void log(String message, Throwable throwable)
+        {
+        }
+
+        public void removeAttribute(String name)
+        {
+            attributes.remove(name);
+        }
+
+        public void setAttribute(String name, Object object)
+        {
+            if (object != null)
+            {
+                attributes.put(name, object);
+            }
+            else
+            {
+                removeAttribute(name);
+            }
+        }
+
+        public boolean setInitParameter(String name, String value)
+        {
+            return false;
+        }
+
+        public void setSessionTrackingModes(Set<SessionTrackingMode> modes)
+        {
+        }
+    }
+
     private Bundle bundle;
     private HttpContext httpContext;
     private AttributeListener listener;
@@ -45,70 +388,13 @@
     public void setUp()
     {
         this.bundle = Mockito.mock(Bundle.class);
-        ServletContext globalContext = Mockito.mock(ServletContext.class);
+        ServletContext globalContext = new MockServletContext();
         this.httpContext = Mockito.mock(HttpContext.class);
         this.listener = new AttributeListener();
         this.context = new ServletContextImpl(this.bundle, globalContext, this.httpContext, this.listener, false);
     }
 
     @Test
-    public void testGetResource()
-        throws Exception
-    {
-        URL url = getClass().getResource("resource.txt");
-        Assert.assertNotNull(url);
-
-        Mockito.when(this.httpContext.getResource("resource.txt")).thenReturn(url);
-        Assert.assertNull(this.context.getResource("/notfound.txt"));
-        Assert.assertEquals(url, this.context.getResource("/resource.txt"));
-    }
-
-    @Test
-    public void testGetResourceAsStream()
-        throws Exception
-    {
-        URL url = getClass().getResource("resource.txt");
-        Assert.assertNotNull(url);
-
-        Mockito.when(this.httpContext.getResource("resource.txt")).thenReturn(url);
-        Assert.assertNull(this.context.getResourceAsStream("/notfound.txt"));
-        Assert.assertNotNull(this.context.getResourceAsStream("/resource.txt"));
-    }
-
-    @Test
-    public void testGetResourcePaths()
-    {
-        HashSet<String> paths = new HashSet<String>(Arrays.asList("/some/path/1", "/some/path/2"));
-        Mockito.when(this.bundle.getEntryPaths("some/path")).thenReturn(Collections.enumeration(paths));
-
-        Set set = this.context.getResourcePaths("/some/path");
-        Assert.assertNotNull(set);
-        Assert.assertEquals(2, set.size());
-        Assert.assertTrue(set.contains("/some/path/1"));
-        Assert.assertTrue(set.contains("/some/path/2"));
-    }
-
-    @Test
-    public void testGetRealPath()
-    {
-        Assert.assertNull(this.context.getRealPath("path"));
-    }
-
-    @Test
-    public void testGetInitParameter()
-    {
-        Assert.assertNull(this.context.getInitParameter("key1"));
-    }
-
-    @Test
-    public void testGetInitParameterNames()
-    {
-        Enumeration e = this.context.getInitParameterNames();
-        Assert.assertNotNull(e);
-        Assert.assertFalse(e.hasMoreElements());
-    }
-
-    @Test
     public void testGetAttribute()
     {
         Assert.assertNull(this.context.getAttribute("key1"));
@@ -151,6 +437,91 @@
     }
 
     @Test
+    public void testGetInitParameter()
+    {
+        Assert.assertNull(this.context.getInitParameter("key1"));
+    }
+
+    @Test
+    public void testGetInitParameterNames()
+    {
+        Enumeration e = this.context.getInitParameterNames();
+        Assert.assertNotNull(e);
+        Assert.assertFalse(e.hasMoreElements());
+    }
+
+    @Test
+    public void testGetMimeType()
+    {
+        Mockito.when(this.httpContext.getMimeType("file.xml")).thenReturn("some-other-format");
+        Assert.assertEquals("some-other-format", this.context.getMimeType("file.xml"));
+        Assert.assertEquals("text/plain", this.context.getMimeType("file.txt"));
+    }
+
+    @Test
+    public void testGetRealPath()
+    {
+        Assert.assertNull(this.context.getRealPath("path"));
+    }
+
+    @Test
+    public void testGetResource() throws Exception
+    {
+        URL url = getClass().getResource("resource.txt");
+        Assert.assertNotNull(url);
+
+        Mockito.when(this.httpContext.getResource("resource.txt")).thenReturn(url);
+        Assert.assertNull(this.context.getResource("/notfound.txt"));
+        Assert.assertEquals(url, this.context.getResource("/resource.txt"));
+    }
+
+    @Test
+    public void testGetResourceAsStream() throws Exception
+    {
+        URL url = getClass().getResource("resource.txt");
+        Assert.assertNotNull(url);
+
+        Mockito.when(this.httpContext.getResource("resource.txt")).thenReturn(url);
+        Assert.assertNull(this.context.getResourceAsStream("/notfound.txt"));
+        Assert.assertNotNull(this.context.getResourceAsStream("/resource.txt"));
+    }
+
+    @Test
+    public void testGetResourcePaths()
+    {
+        HashSet<String> paths = new HashSet<String>(Arrays.asList("/some/path/1", "/some/path/2"));
+        Mockito.when(this.bundle.getEntryPaths("some/path")).thenReturn(Collections.enumeration(paths));
+
+        Set set = this.context.getResourcePaths("/some/path");
+        Assert.assertNotNull(set);
+        Assert.assertEquals(2, set.size());
+        Assert.assertTrue(set.contains("/some/path/1"));
+        Assert.assertTrue(set.contains("/some/path/2"));
+    }
+
+    @Test
+    public void testGetServlet() throws Exception
+    {
+        Assert.assertNull(this.context.getServlet("test"));
+    }
+
+    @Test
+    public void testGetServletNames()
+    {
+        Enumeration e = this.context.getServletNames();
+        Assert.assertNotNull(e);
+        Assert.assertFalse(e.hasMoreElements());
+    }
+
+    @Test
+    public void testGetServlets()
+    {
+        Enumeration e = this.context.getServlets();
+        Assert.assertNotNull(e);
+        Assert.assertFalse(e.hasMoreElements());
+    }
+
+    @Test
     public void testGetSharedAttribute()
     {
         ServletContext globalContext = new MockServletContext();
@@ -295,7 +666,6 @@
         Assert.assertFalse(e.hasMoreElements());
     }
 
-
     @Test
     public void testGetUnsharedAttribute()
     {
@@ -375,39 +745,7 @@
     }
 
     @Test
-    public void testGetServlet()
-        throws Exception
-    {
-        Assert.assertNull(this.context.getServlet("test"));
-    }
-
-    @Test
-    public void testGetServletNames()
-    {
-        Enumeration e = this.context.getServletNames();
-        Assert.assertNotNull(e);
-        Assert.assertFalse(e.hasMoreElements());
-    }
-
-    @Test
-    public void testGetServlets()
-    {
-        Enumeration e = this.context.getServlets();
-        Assert.assertNotNull(e);
-        Assert.assertFalse(e.hasMoreElements());
-    }
-
-    @Test
-    public void testGetMimeType()
-    {
-        Mockito.when(this.httpContext.getMimeType("file.xml")).thenReturn("some-other-format");
-        Assert.assertEquals("some-other-format", this.context.getMimeType("file.xml"));
-        Assert.assertEquals("text/plain", this.context.getMimeType("file.txt"));
-    }
-
-    @Test
-    public void testHandleSecurity()
-        throws Exception
+    public void testHandleSecurity() throws Exception
     {
         HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
         HttpServletResponse res = Mockito.mock(HttpServletResponse.class);
@@ -418,206 +756,4 @@
         Mockito.when(this.httpContext.handleSecurity(req, res)).thenReturn(false);
         Assert.assertFalse(this.context.handleSecurity(req, res));
     }
-
-    private static class AttributeListener implements ServletContextAttributeListener
-    {
-
-        private int type;
-
-        private String name;
-
-        private Object value;
-
-        public void attributeAdded(ServletContextAttributeEvent scab)
-        {
-            setData(1, scab);
-        }
-
-        public void attributeRemoved(ServletContextAttributeEvent scab)
-        {
-            setData(2, scab);
-        }
-
-        public void attributeReplaced(ServletContextAttributeEvent scab)
-        {
-            setData(3, scab);
-        }
-
-        private void setData(int type, ServletContextAttributeEvent scab)
-        {
-            this.type = type;
-            this.name = scab.getName();
-            this.value = scab.getValue();
-        }
-
-        void checkAdded(String name, Object value)
-        {
-            check(1, name, value);
-        }
-
-        void checkRemoved(String name, Object value)
-        {
-            check(2, name, value);
-        }
-
-        void checkReplaced(String name, Object value)
-        {
-            check(3, name, value);
-        }
-
-        void checkNull()
-        {
-            check(0, null, null);
-        }
-
-        private void check(int type, String name, Object value)
-        {
-            try
-            {
-                Assert.assertEquals(type, this.type);
-                Assert.assertEquals(name, this.name);
-                Assert.assertEquals(value, this.value);
-            }
-            finally
-            {
-                this.type = 0;
-                this.name = null;
-                this.value = null;
-            }
-        }
-    }
-
-    private class MockServletContext implements ServletContext {
-
-        private Dictionary attributes = new Hashtable();
-
-        public Object getAttribute(String name)
-        {
-            return attributes.get(name);
-        }
-
-        public Enumeration getAttributeNames()
-        {
-            return attributes.keys();
-        }
-
-        public void setAttribute(String name, Object object)
-        {
-            if (object != null)
-            {
-                attributes.put(name, object);
-            }
-            else
-            {
-                removeAttribute(name);
-            }
-        }
-
-        public void removeAttribute(String name)
-        {
-            attributes.remove(name);
-        }
-
-        public String getContextPath()
-        {
-            return null;
-        }
-
-        public ServletContext getContext(String uripath)
-        {
-            return null;
-        }
-
-        public int getMajorVersion()
-        {
-            return 0;
-        }
-
-        public int getMinorVersion()
-        {
-            return 0;
-        }
-
-        public String getMimeType(String file)
-        {
-            return null;
-        }
-
-        public Set getResourcePaths(String path)
-        {
-            return null;
-        }
-
-        public URL getResource(String path)
-        {
-            return null;
-        }
-
-        public InputStream getResourceAsStream(String path)
-        {
-            return null;
-        }
-
-        public RequestDispatcher getRequestDispatcher(String path)
-        {
-            return null;
-        }
-
-        public RequestDispatcher getNamedDispatcher(String name)
-        {
-            return null;
-        }
-
-        public Servlet getServlet(String name)
-        {
-            return null;
-        }
-
-        public Enumeration getServlets()
-        {
-            return null;
-        }
-
-        public Enumeration getServletNames()
-        {
-            return null;
-        }
-
-        public void log(String msg)
-        {
-        }
-
-        public void log(Exception exception, String msg)
-        {
-        }
-
-        public void log(String message, Throwable throwable)
-        {
-        }
-
-        public String getRealPath(String path)
-        {
-            return null;
-        }
-
-        public String getServerInfo()
-        {
-            return null;
-        }
-
-        public String getInitParameter(String name)
-        {
-            return null;
-        }
-
-        public Enumeration getInitParameterNames()
-        {
-            return null;
-        }
-
-        public String getServletContextName()
-        {
-            return null;
-        }
-    }
 }
diff --git a/http/bridge/pom.xml b/http/bridge/pom.xml
index 3268762..fbb564b 100644
--- a/http/bridge/pom.xml
+++ b/http/bridge/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Bridge</name>
     <artifactId>org.apache.felix.http.bridge</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -68,7 +68,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/bundle/pom.xml b/http/bundle/pom.xml
index 2a0ca00..c8b9f58 100644
--- a/http/bundle/pom.xml
+++ b/http/bundle/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Bundle</name>
     <artifactId>org.apache.felix.http.bundle</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -86,7 +86,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/cometd/pom.xml b/http/cometd/pom.xml
index 9ce224e..ff7c8e2 100644
--- a/http/cometd/pom.xml
+++ b/http/cometd/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Cometd</name>
     <artifactId>org.apache.felix.http.cometd</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -81,7 +81,7 @@
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/itest/pom.xml b/http/itest/pom.xml
new file mode 100644
index 0000000..708876c
--- /dev/null
+++ b/http/itest/pom.xml
@@ -0,0 +1,180 @@
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.http.parent</artifactId>
+        <version>3-SNAPSHOT</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <name>Apache Felix Http Integration Tests</name>
+    <artifactId>org.apache.felix.http.itest</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/http/sslfilter</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/trunk/http/sslfilter</developerConnection>
+        <url>http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/</url>
+    </scm>
+    
+    <properties>
+    	<felix.http.api.version>2.3.0-SNAPSHOT</felix.http.api.version>
+		<pax.exam.version>2.4.0</pax.exam.version>
+		<pax.exam.plugin.version>1.2.4</pax.exam.plugin.version>
+		<pax.url.aether.version>1.4.0</pax.url.aether.version>
+		<pax.swissbox.version>1.3.1</pax.swissbox.version>
+		<pax.runner.version>1.7.6</pax.runner.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.http.api</artifactId>
+            <version>${felix.http.api.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.http.jetty</artifactId>
+            <version>${felix.http.api.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.8.2</version>
+            <scope>test</scope>
+        </dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.exam</groupId>
+			<artifactId>pax-exam-junit4</artifactId>
+			<version>${pax.exam.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.exam</groupId>
+			<artifactId>pax-exam-container-forked</artifactId>
+			<version>${pax.exam.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.runner</groupId>
+			<artifactId>pax-runner-no-jcl</artifactId>
+			<version>${pax.runner.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.exam</groupId>
+			<artifactId>pax-exam-link-assembly</artifactId>
+			<version>${pax.exam.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.exam</groupId>
+			<artifactId>pax-exam-link-mvn</artifactId>
+			<version>${pax.exam.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.url</groupId>
+			<artifactId>pax-url-aether</artifactId>
+			<version>${pax.url.aether.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.ops4j.pax.url</groupId>
+			<artifactId>pax-url-wrap</artifactId>
+			<version>${pax.url.aether.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.inject</groupId>
+			<artifactId>javax.inject</artifactId>
+			<version>1</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.framework</artifactId>
+			<version>4.0.2</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<version>1.6.0</version>
+			<scope>compile</scope>
+		</dependency>
+    </dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<target>1.6</target>
+					<source>1.6</source>
+				</configuration>
+			</plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>maven-paxexam-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-config</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+		</plugins>
+	</build>
+
+</project>
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java
new file mode 100644
index 0000000..8fa35ac
--- /dev/null
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java
@@ -0,0 +1,440 @@
+/*
+ * 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.itest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.ops4j.pax.exam.Constants.START_LEVEL_SYSTEM_BUNDLES;
+import static org.ops4j.pax.exam.Constants.START_LEVEL_TEST_BUNDLE;
+import static org.ops4j.pax.exam.CoreOptions.bootDelegationPackage;
+import static org.ops4j.pax.exam.CoreOptions.cleanCaches;
+import static org.ops4j.pax.exam.CoreOptions.felix;
+import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.url;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Scanner;
+import java.util.concurrent.CountDownLatch;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.http.api.ExtHttpService;
+import org.junit.After;
+import org.junit.Before;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Base class for integration tests.
+ *  
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class BaseIntegrationTest
+{
+    protected static class TestFilter implements Filter
+    {
+        private final CountDownLatch m_initLatch;
+        private final CountDownLatch m_destroyLatch;
+
+        public TestFilter(CountDownLatch initLatch, CountDownLatch destroyLatch)
+        {
+            m_initLatch = initLatch;
+            m_destroyLatch = destroyLatch;
+        }
+
+        public void destroy()
+        {
+            if (m_destroyLatch != null)
+            {
+                m_destroyLatch.countDown();
+            }
+        }
+
+        public final void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException
+        {
+            filter((HttpServletRequest) req, (HttpServletResponse) resp, chain);
+        }
+
+        public void init(FilterConfig config) throws ServletException
+        {
+            if (m_initLatch != null)
+            {
+                m_initLatch.countDown();
+            }
+        }
+
+        protected void filter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException
+        {
+            ((HttpServletResponse) resp).setStatus(HttpServletResponse.SC_OK);
+        }
+    }
+
+    protected static class TestServlet extends HttpServlet
+    {
+        private static final long serialVersionUID = 1L;
+
+        private final CountDownLatch m_initLatch;
+        private final CountDownLatch m_destroyLatch;
+
+        public TestServlet(CountDownLatch initLatch, CountDownLatch destroyLatch)
+        {
+            m_initLatch = initLatch;
+            m_destroyLatch = destroyLatch;
+        }
+
+        @Override
+        public void destroy()
+        {
+            super.destroy();
+            if (m_destroyLatch != null)
+            {
+                m_destroyLatch.countDown();
+            }
+        }
+
+        @Override
+        public void init() throws ServletException
+        {
+            super.init();
+            if (m_initLatch != null)
+            {
+                m_initLatch.countDown();
+            }
+        }
+
+        @Override
+        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+        {
+            resp.setStatus(HttpServletResponse.SC_OK);
+        }
+    }
+
+    private static final int DEFAULT_TIMEOUT = 10000;
+
+    protected static final String ORG_APACHE_FELIX_HTTP_JETTY = "org.apache.felix.http.jetty";
+
+    protected static void assertContent(int expectedRC, String expected, URL url) throws IOException
+    {
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+
+        int rc = conn.getResponseCode();
+        assertEquals("Unexpected response code,", expectedRC, rc);
+
+        if (rc >= 200 && rc < 500)
+        {
+            InputStream is = null;
+            try
+            {
+                is = conn.getInputStream();
+                assertEquals(expected, slurpAsString(is));
+            }
+            finally
+            {
+                close(is);
+                conn.disconnect();
+            }
+        }
+        else
+        {
+            InputStream is = null;
+            try
+            {
+                is = conn.getErrorStream();
+                assertEquals(expected, slurpAsString(is));
+            }
+            finally
+            {
+                close(is);
+                conn.disconnect();
+            }
+        }
+    }
+
+    protected static void assertContent(String expected, URL url) throws IOException
+    {
+        assertContent(200, expected, url);
+    }
+
+    protected static void assertResponseCode(int expected, URL url) throws IOException
+    {
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        try
+        {
+            assertEquals(expected, conn.getResponseCode());
+        }
+        finally
+        {
+            conn.disconnect();
+        }
+    }
+
+    protected static void close(Closeable resource)
+    {
+        if (resource != null)
+        {
+            try
+            {
+                resource.close();
+            }
+            catch (IOException e)
+            {
+                // Ignore...
+            }
+        }
+    }
+
+    protected static URL createURL(String path)
+    {
+        if (path == null)
+        {
+            path = "";
+        }
+        while (path.startsWith("/"))
+        {
+            path = path.substring(1);
+        }
+        int port = Integer.getInteger("org.osgi.service.http.port", 8080);
+        try
+        {
+            return new URL(String.format("http://localhost:%d/%s", port, path));
+        }
+        catch (MalformedURLException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected static String slurpAsString(InputStream is) throws IOException
+    {
+        // See <weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner_1.html>
+        Scanner scanner = new Scanner(is, "UTF-8");
+        try
+        {
+            scanner.useDelimiter("\\A");
+
+            return scanner.hasNext() ? scanner.next() : null;
+        }
+        finally
+        {
+            try
+            {
+                scanner.close();
+            }
+            catch (Exception e)
+            {
+                // Ignore...
+            }
+        }
+    }
+
+    @Inject
+    protected volatile BundleContext m_context;
+
+    @Configuration
+    public Option[] config()
+    {
+        return options(
+            bootDelegationPackage("sun.*"),
+            cleanCaches(),
+            CoreOptions.systemProperty("logback.configurationFile").value("file:src/test/resources/logback.xml"), //
+//            CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8787"),
+
+            mavenBundle("org.slf4j", "slf4j-api").version("1.6.5").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            mavenBundle("ch.qos.logback", "logback-core").version("1.0.6").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            mavenBundle("ch.qos.logback", "logback-classic").version("1.0.6").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
+            url("link:classpath:META-INF/links/org.ops4j.pax.exam.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.pax.exam.inject.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.pax.extender.service.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.base.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.core.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.extender.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.lifecycle.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.framework.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            url("link:classpath:META-INF/links/org.apache.geronimo.specs.atinject.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
+            mavenBundle("org.apache.felix", ORG_APACHE_FELIX_HTTP_JETTY).versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
+            junitBundles(), frameworkStartLevel(START_LEVEL_TEST_BUNDLE), felix());
+    }
+
+    @Before
+    public void setUp() throws Exception
+    {
+        assertNotNull("No bundle context?!", m_context);
+    }
+
+    @After
+    public void tearDown() throws Exception
+    {
+        Bundle bundle = getHttpJettyBundle();
+        // Restart the HTTP-service to clean all registrations...
+        if (bundle.getState() == Bundle.ACTIVE)
+        {
+            bundle.stop();
+            bundle.start();
+        }
+    }
+
+    /**
+     * Waits for a service to become available in certain time interval.
+     * @param serviceName
+     * @return
+     * @throws Exception
+     */
+    protected <T> T awaitService(String serviceName) throws Exception
+    {
+        ServiceTracker tracker = new ServiceTracker(m_context, serviceName, null);
+        tracker.open();
+        T result;
+        try
+        {
+            result = (T) tracker.waitForService(DEFAULT_TIMEOUT);
+        }
+        finally
+        {
+            tracker.close();
+        }
+        return result;
+    }
+
+    /**
+     * @param bsn
+     * @return
+     */
+    protected Bundle findBundle(String bsn)
+    {
+        for (Bundle bundle : m_context.getBundles())
+        {
+            if (bsn.equals(bundle.getSymbolicName()))
+            {
+                return bundle;
+            }
+        }
+        return null;
+    }
+
+    protected ExtHttpService getExtHttpService()
+    {
+        return getService(ExtHttpService.class.getName());
+    }
+
+    protected Bundle getHttpJettyBundle()
+    {
+        Bundle b = findBundle(ORG_APACHE_FELIX_HTTP_JETTY);
+        assertNotNull("Filestore bundle not found?!", b);
+        return b;
+    }
+
+    protected HttpService getHttpService()
+    {
+        return getService(HttpService.class.getName());
+    }
+
+    /**
+     * Obtains a service without waiting for it to become available.
+     * @param serviceName
+     * @return
+     */
+    protected <T> T getService(String serviceName)
+    {
+        ServiceTracker tracker = new ServiceTracker(m_context, serviceName, null);
+        tracker.open();
+        T result;
+        try
+        {
+            result = (T) tracker.getService();
+        }
+        finally
+        {
+            tracker.close();
+        }
+        return result;
+    }
+
+    protected void register(String pattern, Filter filter) throws ServletException, NamespaceException
+    {
+        register(pattern, filter, null);
+    }
+
+    protected void register(String pattern, Filter servlet, HttpContext context) throws ServletException, NamespaceException
+    {
+        getExtHttpService().registerFilter(servlet, pattern, null, 0, context);
+    }
+
+    protected void register(String alias, Servlet servlet) throws ServletException, NamespaceException
+    {
+        register(alias, servlet, null);
+    }
+
+    protected void register(String alias, Servlet servlet, HttpContext context) throws ServletException, NamespaceException
+    {
+        getHttpService().registerServlet(alias, servlet, null, context);
+    }
+
+    protected void register(String alias, String name) throws ServletException, NamespaceException
+    {
+        register(alias, name, null);
+    }
+
+    protected void register(String alias, String name, HttpContext context) throws ServletException, NamespaceException
+    {
+        getExtHttpService().registerResources(alias, name, context);
+    }
+
+    protected void unregister(Filter filter) throws ServletException, NamespaceException
+    {
+        getExtHttpService().unregisterFilter(filter);
+    }
+
+    protected void unregister(Servlet servlet) throws ServletException, NamespaceException
+    {
+        getExtHttpService().unregisterServlet(servlet);
+    }
+
+    protected void unregister(String alias) throws ServletException, NamespaceException
+    {
+        getExtHttpService().unregister(alias);
+    }
+}
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/HttpJettyTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/HttpJettyTest.java
new file mode 100644
index 0000000..76e354f
--- /dev/null
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/HttpJettyTest.java
@@ -0,0 +1,309 @@
+/*
+ * 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.itest;
+
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpContext;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@RunWith(JUnit4TestRunner.class)
+public class HttpJettyTest extends BaseIntegrationTest
+{
+
+    /**
+     * Tests the starting of Jetty.
+     */
+    @Test
+    public void test00_StartJettyOk() throws Exception
+    {
+        assertTrue(getHttpJettyBundle().getState() == Bundle.ACTIVE);
+
+        assertResponseCode(SC_NOT_FOUND, createURL("/"));
+    }
+
+    /**
+     * Tests the starting of Jetty.
+     */
+    @Test
+    public void test00_StopJettyOk() throws Exception
+    {
+        Bundle bundle = getHttpJettyBundle();
+
+        assertTrue(bundle.getState() == Bundle.ACTIVE);
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+        CountDownLatch destroyLatch = new CountDownLatch(1);
+
+        TestServlet servlet = new TestServlet(initLatch, destroyLatch);
+
+        register("/test", servlet);
+
+        assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+
+        assertResponseCode(SC_OK, createURL("/test"));
+
+        bundle.stop();
+
+        assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+
+        try
+        {
+            createURL("/test").openStream();
+            fail("Could connect to stopped Jetty instance?!");
+        }
+        catch (ConnectException e)
+        {
+            // Ok; expected...
+        }
+
+        bundle.start();
+
+        Thread.sleep(500); // Allow Jetty to start (still done asynchronously)...
+
+        assertResponseCode(SC_NOT_FOUND, createURL("/test"));
+    }
+
+    /**
+     * Tests that we can register a filter with Jetty and that its lifecycle is correctly controlled.
+     */
+    @Test
+    public void testRegisterFilterLifecycleOk() throws Exception
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        CountDownLatch destroyLatch = new CountDownLatch(1);
+
+        TestFilter filter = new TestFilter(initLatch, destroyLatch);
+
+        register("/test", filter);
+
+        assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+
+        unregister(filter);
+
+        assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    /**
+     * Tests that we can register a servlet with Jetty and that its lifecycle is correctly controlled.
+     */
+    @Test
+    public void testRegisterServletLifecycleOk() throws Exception
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        CountDownLatch destroyLatch = new CountDownLatch(1);
+
+        TestServlet servlet = new TestServlet(initLatch, destroyLatch);
+
+        register("/test", servlet);
+
+        assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+
+        unregister(servlet);
+
+        assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testUseServletContextOk() throws Exception
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        CountDownLatch destroyLatch = new CountDownLatch(1);
+
+        HttpContext context = new HttpContext()
+        {
+            public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException
+            {
+                return true;
+            }
+
+            public URL getResource(String name)
+            {
+                try
+                {
+                    File f = new File("src/test/resources/resource/" + name);
+                    if (f.exists())
+                    {
+                        return f.toURI().toURL();
+                    }
+                }
+                catch (MalformedURLException e)
+                {
+                    fail();
+                }
+                return null;
+            }
+
+            public String getMimeType(String name)
+            {
+                return null;
+            }
+        };
+
+        TestServlet servlet = new TestServlet(initLatch, destroyLatch)
+        {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public void init(ServletConfig config) throws ServletException
+            {
+                ServletContext context = config.getServletContext();
+                try
+                {
+                    assertEquals("", context.getContextPath());
+                    assertNotNull(context.getResource("test.html"));
+                    assertNotNull(context.getRealPath("test.html"));
+                }
+                catch (MalformedURLException e)
+                {
+                    fail();
+                }
+
+                super.init(config);
+            }
+        };
+
+        register("/foo", servlet, context);
+
+        URL testURL = createURL("/foo");
+
+        assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+
+        assertResponseCode(SC_OK, testURL);
+
+        unregister(servlet);
+
+        assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+
+        assertResponseCode(SC_NOT_FOUND, testURL);
+    }
+
+    /**
+     * Tests that we can register servlets and filters together.
+     */
+    @Test
+    public void testHandleMultipleRegistrationsOk() throws Exception
+    {
+        CountDownLatch initLatch = new CountDownLatch(3);
+        CountDownLatch destroyLatch = new CountDownLatch(3);
+
+        TestServlet servlet1 = new TestServlet(initLatch, destroyLatch)
+        {
+            private static final long serialVersionUID = 1L;
+
+            final AtomicLong m_count = new AtomicLong();
+
+            @Override
+            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                resp.setStatus(SC_OK);
+                resp.getWriter().printf("1.%d", m_count.incrementAndGet());
+                resp.flushBuffer();
+            }
+        };
+
+        TestServlet servlet2 = new TestServlet(initLatch, destroyLatch)
+        {
+            private static final long serialVersionUID = 1L;
+
+            final AtomicLong m_count = new AtomicLong();
+
+            @Override
+            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                resp.setStatus(SC_OK);
+                resp.getWriter().printf("2.%d", m_count.incrementAndGet());
+                resp.flushBuffer();
+            }
+        };
+
+        TestFilter filter = new TestFilter(initLatch, destroyLatch)
+        {
+            @Override
+            protected void filter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException
+            {
+                String param = req.getParameter("param");
+                if ("forbidden".equals(param))
+                {
+                    resp.reset();
+                    resp.sendError(SC_FORBIDDEN);
+                    resp.flushBuffer();
+                }
+                else
+                {
+                    chain.doFilter(req, resp);
+                }
+            }
+        };
+
+        register("/test1", servlet1);
+        register("/test2", servlet2);
+        register("/test.*", filter);
+
+        assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+
+        assertContent("1.1", createURL("/test1"));
+        assertContent("2.1", createURL("/test2"));
+        assertContent("2.2", createURL("/test2"));
+        assertContent("1.2", createURL("/test1"));
+        assertContent("2.3", createURL("/test2"));
+
+        assertResponseCode(SC_FORBIDDEN, createURL("/test2?param=forbidden"));
+        assertResponseCode(SC_NOT_FOUND, createURL("/?test=forbidden"));
+
+        assertContent("2.4", createURL("/test2"));
+        assertContent("1.3", createURL("/test1"));
+
+        assertResponseCode(SC_FORBIDDEN, createURL("/test?param=forbidden"));
+
+        unregister(servlet1);
+        unregister(servlet2);
+        unregister(filter);
+
+        assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/ResourceTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/ResourceTest.java
new file mode 100644
index 0000000..02cf276
--- /dev/null
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/ResourceTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.itest;
+
+import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.service.http.HttpContext;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@RunWith(JUnit4TestRunner.class)
+public class ResourceTest extends BaseIntegrationTest
+{
+
+    @Test
+    public void testHandleResourceRegistrationOk() throws Exception
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        CountDownLatch destroyLatch = new CountDownLatch(1);
+
+        HttpContext context = new HttpContext()
+        {
+            public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException
+            {
+                return true;
+            }
+
+            public URL getResource(String name)
+            {
+                try
+                {
+                    File f = new File("src/test/resources/" + name);
+                    if (f.exists())
+                    {
+                        return f.toURI().toURL();
+                    }
+                }
+                catch (MalformedURLException e)
+                {
+                    fail();
+                }
+                return null;
+            }
+
+            public String getMimeType(String name)
+            {
+                return null;
+            }
+        };
+
+        TestServlet servlet = new TestServlet(initLatch, destroyLatch);
+
+        register("/", "/resource", context);
+        register("/test", servlet, context);
+
+        URL testHtmlURL = createURL("/test.html");
+        URL testURL = createURL("/test");
+
+        assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+
+        assertResponseCode(SC_OK, testHtmlURL);
+        assertResponseCode(SC_OK, testURL);
+
+        unregister(servlet);
+
+        assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+
+        assertResponseCode(SC_OK, testHtmlURL);
+        assertResponseCode(SC_NOT_FOUND, testURL);
+
+        unregister("/");
+
+        assertResponseCode(SC_NOT_FOUND, testHtmlURL);
+    }
+}
diff --git a/http/itest/src/test/resources/logback.xml b/http/itest/src/test/resources/logback.xml
new file mode 100644
index 0000000..03dedea
--- /dev/null
+++ b/http/itest/src/test/resources/logback.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<configuration>
+	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+			</pattern>
+		</encoder>
+	</appender>
+
+	<root level="WARN">
+		<appender-ref ref="STDOUT" />
+	</root>
+
+	<logger name="org.ops4j" level="WARN" />
+</configuration>
diff --git a/http/itest/src/test/resources/resource/test.html b/http/itest/src/test/resources/resource/test.html
new file mode 100644
index 0000000..5573d33
--- /dev/null
+++ b/http/itest/src/test/resources/resource/test.html
@@ -0,0 +1,19 @@
+<!--
+    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.
+-->
+<html><body><h1>TEST</h1></body></html>
\ No newline at end of file
diff --git a/http/jetty/pom.xml b/http/jetty/pom.xml
index be63e21..d308d4c 100644
--- a/http/jetty/pom.xml
+++ b/http/jetty/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Jetty</name>
     <artifactId>org.apache.felix.http.jetty</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
     
     <scm>
@@ -93,7 +93,7 @@
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
         </dependency>
         <dependency>
             <groupId>org.eclipse.jetty</groupId>
diff --git a/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java b/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
index b0eea3c..3a0b069 100644
--- a/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
+++ b/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
@@ -22,6 +22,7 @@
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -34,6 +35,10 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 
+import javax.servlet.ServletContext;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+
 import org.apache.felix.http.base.internal.DispatcherServlet;
 import org.apache.felix.http.base.internal.EventDispatcher;
 import org.apache.felix.http.base.internal.HttpServiceController;
@@ -67,8 +72,6 @@
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
-import javax.servlet.ServletContext;
-
 public final class JettyService extends AbstractLifeCycle.AbstractLifeCycleListener implements BundleTrackerCustomizer, ServiceTrackerCustomizer
 {
     /** PID for configuration of the HTTP service. */
@@ -399,12 +402,15 @@
         final SessionManager manager = context.getSessionHandler().getSessionManager();
 
         manager.setMaxInactiveInterval(this.config.getSessionTimeout() * 60);
-
-        manager.setSessionCookie(this.config.getProperty(SessionManager.__SessionCookieProperty, SessionManager.__DefaultSessionCookie));
         manager.setSessionIdPathParameterName(this.config.getProperty(SessionManager.__SessionIdPathParameterNameProperty, SessionManager.__DefaultSessionIdPathParameterName));
-        manager.setSessionDomain(this.config.getProperty(SessionManager.__SessionDomainProperty, SessionManager.__DefaultSessionDomain));
-        manager.setSessionPath(this.config.getProperty(SessionManager.__SessionPathProperty, context.getContextPath()));
-        manager.setMaxCookieAge(this.config.getIntProperty(SessionManager.__MaxAgeProperty, -1));
+        manager.setCheckingRemoteSessionIdEncoding(this.config.getBooleanProperty(SessionManager.__CheckRemoteSessionEncoding, true));
+        manager.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE)); // XXX
+
+        SessionCookieConfig cookieConfig = manager.getSessionCookieConfig();
+        cookieConfig.setName(this.config.getProperty(SessionManager.__SessionCookieProperty, SessionManager.__DefaultSessionCookie));
+        cookieConfig.setDomain(this.config.getProperty(SessionManager.__SessionDomainProperty, SessionManager.__DefaultSessionDomain));
+        cookieConfig.setPath(this.config.getProperty(SessionManager.__SessionPathProperty, context.getContextPath()));
+        cookieConfig.setMaxAge(this.config.getIntProperty(SessionManager.__MaxAgeProperty, -1));
     }
 
     private String getEndpoint(final Connector listener, final InetAddress ia)
diff --git a/http/parent/pom.xml b/http/parent/pom.xml
index 4aaa7ab..a8b4562 100755
--- a/http/parent/pom.xml
+++ b/http/parent/pom.xml
@@ -39,10 +39,10 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    	<jetty.version>7.6.13.v20130916</jetty.version>
+    	<jetty.version>8.1.14.v20131031</jetty.version>
     	<cometd.version>2.7.0</cometd.version>
     	<http.service.version>1.2.0</http.service.version>
-    	<servlet.version>2.5</servlet.version>
+    	<servlet.version>3.0.1</servlet.version>
 
     	<http.api.version>2.0.4</http.api.version>
     </properties>
@@ -109,7 +109,7 @@
         <dependencies>
             <dependency>
                 <groupId>javax.servlet</groupId>
-                <artifactId>servlet-api</artifactId>
+                <artifactId>javax.servlet-api</artifactId>
                 <version>${servlet.version}</version>
                 <scope>provided</scope>
             </dependency>
diff --git a/http/pom.xml b/http/pom.xml
index 3988c7c..67cdee2 100644
--- a/http/pom.xml
+++ b/http/pom.xml
@@ -49,6 +49,7 @@
         <module>cometd</module>
         <module>bundle</module>
         <module>sslfilter</module>
+        <module>itest</module>
         <module>samples/filter</module>
         <module>samples/bridge</module>
         <module>samples/whiteboard</module>
diff --git a/http/proxy/pom.xml b/http/proxy/pom.xml
index 3611fe1..ec36e4a 100644
--- a/http/proxy/pom.xml
+++ b/http/proxy/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Proxy</name>
     <artifactId>org.apache.felix.http.proxy</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -59,7 +59,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/samples/bridge/pom.xml b/http/samples/bridge/pom.xml
index 4dc9607..7371ffd 100644
--- a/http/samples/bridge/pom.xml
+++ b/http/samples/bridge/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Samples - Bridge</name>
     <artifactId>org.apache.felix.http.samples.bridge</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>war</packaging>
 
     <scm>
@@ -109,7 +109,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/samples/cometd/pom.xml b/http/samples/cometd/pom.xml
index 5d70968..58d0d43 100644
--- a/http/samples/cometd/pom.xml
+++ b/http/samples/cometd/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Samples - Cometd</name>
     <artifactId>org.apache.felix.http.samples.cometd</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -79,7 +79,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/samples/filter/pom.xml b/http/samples/filter/pom.xml
index bf34cde..d4d9af1 100644
--- a/http/samples/filter/pom.xml
+++ b/http/samples/filter/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Samples - Filter</name>
     <artifactId>org.apache.felix.http.samples.filter</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -75,7 +75,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/samples/whiteboard/pom.xml b/http/samples/whiteboard/pom.xml
index ddb7869..f389ffc 100644
--- a/http/samples/whiteboard/pom.xml
+++ b/http/samples/whiteboard/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Samples - Whiteboard</name>
     <artifactId>org.apache.felix.http.samples.whiteboard</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -75,7 +75,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/http/sslfilter/pom.xml b/http/sslfilter/pom.xml
index 4cb345a..88fe4ee 100644
--- a/http/sslfilter/pom.xml
+++ b/http/sslfilter/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http SSL Filter</name>
     <artifactId>org.apache.felix.http.sslfilter</artifactId>
-    <version>0.0.3-SNAPSHOT</version>
+    <version>0.1.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <scm>
@@ -38,7 +38,7 @@
     </scm>
     
     <properties>
-    	<felix.http.api.version>2.2.2-SNAPSHOT</felix.http.api.version>
+    	<felix.http.api.version>2.3.0-SNAPSHOT</felix.http.api.version>
     </properties>
 
     <build>
@@ -65,7 +65,7 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -81,7 +81,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.http.api</artifactId>
-            <version>2.2.3-SNAPSHOT</version>
+            <version>2.3.0-SNAPSHOT</version>
         </dependency>
 
         <!-- Test Dependencies -->
diff --git a/http/whiteboard/pom.xml b/http/whiteboard/pom.xml
index 1c01584..ef7246c 100644
--- a/http/whiteboard/pom.xml
+++ b/http/whiteboard/pom.xml
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Http Whiteboard</name>
     <artifactId>org.apache.felix.http.whiteboard</artifactId>
-    <version>2.2.3-SNAPSHOT</version>
+    <version>2.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -61,15 +61,18 @@
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.felix</groupId>