You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2022/03/15 08:11:19 UTC

[felix-dev] branch master updated: FELIX-6487 : Update to Jetty 11

This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-dev.git


The following commit(s) were added to refs/heads/master by this push:
     new 23bb5c5  FELIX-6487 : Update to Jetty 11
23bb5c5 is described below

commit 23bb5c55ae6bd74b5db0e343a4f057fe7afb1cc6
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Mar 15 09:11:05 2022 +0100

    FELIX-6487 : Update to Jetty 11
---
 http/{base => base-4.x}/pom.xml                    |   0
 .../http/base/internal/AbstractActivator.java}     |  48 +-
 .../http/base/internal/AbstractHttpActivator.java} |  47 +-
 .../felix/http/base/internal/EventDispatcher.java  |   0
 .../felix/http/base/internal/HttpConfig.java       | 164 ++++
 .../http/base/internal/HttpServiceController.java  |   0
 .../base/internal/console/HttpServicePlugin.java   |   0
 .../base/internal/context/ExtServletContext.java   |   0
 .../internal/context/ExtServletContextWrapper.java |   0
 .../http/base/internal/dispatch/Dispatcher.java    |   0
 .../base/internal/dispatch/DispatcherServlet.java  |   0
 .../base/internal/dispatch/InvocationChain.java    |   0
 .../base/internal/dispatch/MultipartConfig.java    |  76 ++
 .../internal/dispatch/RequestDispatcherImpl.java   |   0
 .../http/base/internal/dispatch/RequestInfo.java   |   0
 .../internal/dispatch/ServletRequestWrapper.java   |   0
 .../internal/dispatch/ServletResponseWrapper.java  |   0
 .../base/internal/handler/FilterConfigImpl.java    |   0
 .../http/base/internal/handler/FilterHandler.java  |   0
 .../handler/HttpServiceServletHandler.java         |   0
 .../base/internal/handler/HttpSessionWrapper.java  |   0
 .../base/internal/handler/ListenerHandler.java     |   0
 .../base/internal/handler/PreprocessorHandler.java |   0
 .../base/internal/handler/ServletConfigImpl.java   |   0
 .../http/base/internal/handler/ServletHandler.java |   0
 .../internal/handler/WhiteboardServletHandler.java |   0
 .../http/base/internal/logger/ConsoleLogger.java   |  81 ++
 .../http/base/internal/logger/InternalLogger.java} |  20 +-
 .../http/base/internal/logger/JDK14Logger.java     |  74 ++
 .../internal/logger/LogServiceEnabledLogger.java   | 158 ++++
 .../base/internal/logger/LogServiceSupport.java    |  40 +
 .../base/internal/logger/R6LogServiceLogger.java   |  46 +
 .../http/base/internal/logger/SystemLogger.java    | 161 ++++
 .../base/internal/registry/ErrorPageRegistry.java  |   0
 .../internal/registry/EventListenerRegistry.java   |   0
 .../base/internal/registry/FilterRegistry.java     |   0
 .../base/internal/registry/HandlerRegistry.java    |   0
 .../http/base/internal/registry/ListenerMap.java   |   0
 .../base/internal/registry/PathResolution.java     |   0
 .../http/base/internal/registry/PathResolver.java} |  20 +-
 .../internal/registry/PathResolverFactory.java     |   0
 .../registry/PerContextHandlerRegistry.java        |   0
 .../base/internal/registry/ServletRegistry.java    |   0
 .../base/internal/registry/ServletResolution.java} |  21 +-
 .../http/base/internal/runtime/AbstractInfo.java   |   0
 .../http/base/internal/runtime/FilterInfo.java     |   0
 .../http/base/internal/runtime/ListenerInfo.java   |   0
 .../base/internal/runtime/PreprocessorInfo.java    |   0
 .../http/base/internal/runtime/ResourceInfo.java   |   0
 .../internal/runtime/ServletContextHelperInfo.java |   0
 .../http/base/internal/runtime/ServletInfo.java    |   0
 .../internal/runtime/WhiteboardServiceInfo.java    |   0
 .../runtime/dto/BaseServletDTOBuilder.java         |   0
 .../internal/runtime/dto/BuilderConstants.java     |   0
 .../internal/runtime/dto/ErrorPageDTOBuilder.java  |   0
 .../base/internal/runtime/dto/FailedDTOHolder.java |   0
 .../internal/runtime/dto/FilterDTOBuilder.java     |   0
 .../internal/runtime/dto/ListenerDTOBuilder.java   |   0
 .../runtime/dto/PreprocessorDTOBuilder.java        |   0
 .../base/internal/runtime/dto/RegistryRuntime.java |   0
 .../runtime/dto/RequestInfoDTOBuilder.java         |   0
 .../internal/runtime/dto/ResourceDTOBuilder.java   |   0
 .../internal/runtime/dto/RuntimeDTOBuilder.java    |   0
 .../runtime/dto/ServletContextDTOBuilder.java      |   0
 .../internal/runtime/dto/ServletDTOBuilder.java    |   0
 .../base/internal/service/DefaultHttpContext.java  |   0
 .../base/internal/service/HttpServiceFactory.java  |   0
 .../internal/service/HttpServiceRuntimeImpl.java   |   0
 .../internal/service/PerBundleHttpServiceImpl.java |   0
 .../base/internal/service/ResourceServlet.java     |   0
 .../base/internal/service/ServletContextImpl.java  |   0
 .../internal/service/ServletContextManager.java    |   0
 .../internal/service/SharedHttpServiceImpl.java    |   0
 .../http/base/internal/util/InternalIdFactory.java |  39 +
 .../felix/http/base/internal/util/MimeTypes.java   | 211 +++++
 .../felix/http/base/internal/util/PatternUtil.java | 144 ++++
 .../http/base/internal/util/ServiceUtils.java      |  89 ++
 .../felix/http/base/internal/util/UriUtils.java    | 368 ++++++++
 .../internal/whiteboard/FailureStateHandler.java   |   0
 .../whiteboard/HttpServiceContextHandler.java      |   0
 .../whiteboard/PerBundleServletContextImpl.java    |   0
 .../whiteboard/RegistrationFailureException.java   |   0
 .../whiteboard/SharedServletContextImpl.java       |   0
 .../whiteboard/WhiteboardContextHandler.java       |   0
 .../internal/whiteboard/WhiteboardManager.java     |   0
 .../internal/whiteboard/tracker/FilterTracker.java |   0
 .../whiteboard/tracker/ListenersTracker.java       |   0
 .../whiteboard/tracker/PreprocessorTracker.java    |   0
 .../whiteboard/tracker/ResourceTracker.java        |   0
 .../tracker/ServletContextHelperTracker.java       |   0
 .../whiteboard/tracker/ServletTracker.java         |   0
 .../tracker/WhiteboardServiceTracker.java          | 125 +++
 .../internal/context/ServletContextImplTest.java   |   0
 .../context/ServletContextManagerTest.java         |   0
 .../internal/handler/FilterConfigImplTest.java     |   0
 .../base/internal/handler/FilterHandlerTest.java   |   0
 .../handler/HttpServiceServletHandlerTest.java     |   0
 .../internal/handler/HttpSessionWrapperTest.java   |   0
 .../internal/handler/ServletConfigImplTest.java    |   0
 .../internal/registry/ErrorPageRegistryTest.java   |   0
 .../registry/EventListenerRegistryTest.java        |   0
 .../base/internal/registry/FilterRegistryTest.java |   0
 .../internal/registry/HandlerRegistryTest.java     |   0
 .../internal/registry/PathResolverFactoryTest.java |   0
 .../registry/PerContextHandlerRegistryTest.java    | 116 +++
 .../internal/registry/ServletRegistryTest.java     |   0
 .../internal/runtime/AbstractInfoOrderingTest.java |   0
 .../base/internal/runtime/ListenerInfoTest.java    |   0
 .../runtime/dto/RuntimeDTOBuilderTest.java         | 734 ++++++++++++++++
 .../internal/service/HttpServiceFactoryTest.java   |   0
 .../http/base/internal/util/MimeTypesTest.java     |  53 ++
 .../http/base/internal/util/PatternUtilTest.java   |  58 ++
 .../http/base/internal/util/UriUtilsTest.java      | 139 +++
 .../whiteboard/FailureStateHandlerTest.java        |   0
 .../felix/http/base/internal/context/resource.txt} |  24 +-
 http/base/README                                   |   5 +
 http/base/pom.xml                                  |  11 +-
 .../felix/http/base/internal/EventDispatcher.java  |   6 +-
 .../http/base/internal/HttpServiceController.java  |  32 +-
 .../base/internal/console/HttpServicePlugin.java   |  42 +-
 .../base/internal/context/ExtServletContext.java   |  19 +-
 .../internal/context/ExtServletContextWrapper.java |  40 +-
 .../http/base/internal/dispatch/Dispatcher.java    |  30 +-
 .../base/internal/dispatch/DispatcherServlet.java  |   8 +-
 .../base/internal/dispatch/InvocationChain.java    |  16 +-
 .../internal/dispatch/RequestDispatcherImpl.java   |  14 +-
 .../http/base/internal/dispatch/RequestInfo.java   |   4 +-
 .../internal/dispatch/ServletRequestWrapper.java   | 106 ++-
 .../internal/dispatch/ServletResponseWrapper.java  |  16 +-
 .../base/internal/handler/FilterConfigImpl.java    |   4 +-
 .../http/base/internal/handler/FilterHandler.java  |  30 +-
 .../handler/HttpServiceServletHandler.java         |  22 +-
 .../base/internal/handler/HttpSessionWrapper.java  |  12 +-
 .../base/internal/handler/ListenerHandler.java     |  10 +-
 .../base/internal/handler/PreprocessorHandler.java |  27 +-
 .../base/internal/handler/ServletConfigImpl.java   |   4 +-
 .../http/base/internal/handler/ServletHandler.java |  25 +-
 .../internal/handler/WhiteboardServletHandler.java |  16 +-
 .../jakartawrappers/AsyncContextWrapper.java       | 109 +++
 .../jakartawrappers/AsyncListenerWrapper.java      |  76 ++
 .../internal/jakartawrappers/CookieWrapper.java    | 111 +++
 .../jakartawrappers/EventListenerWrapper.java      | 229 +++++
 .../jakartawrappers/FilterRegistrationWrapper.java | 115 +++
 .../internal/jakartawrappers/FilterWrapper.java    |  78 ++
 .../jakartawrappers/HttpServletMappingWrapper.java |  73 ++
 .../jakartawrappers/HttpServletRequestWrapper.java | 268 ++++++
 .../HttpServletResponseWrapper.java                | 151 ++++
 .../jakartawrappers/HttpSessionContextWrapper.java |  55 ++
 .../jakartawrappers/HttpSessionWrapper.java        | 132 +++
 .../base/internal/jakartawrappers/PartWrapper.java |  91 ++
 .../PreprocessorWrapper.java}                      |  41 +-
 .../jakartawrappers/PushBuilderWrapper.java        | 116 +++
 .../ReadListenerWrapper.java}                      |  60 +-
 .../jakartawrappers/RequestDispatcherWrapper.java  |  62 ++
 .../jakartawrappers/ServletConfigWrapper.java      |  60 ++
 .../ServletContextHelperWrapper.java               |  85 ++
 .../jakartawrappers/ServletContextWrapper.java     | 417 +++++++++
 .../ServletExceptionUtil.java}                     |  35 +-
 .../ServletExceptionWrapper.java}                  |  44 +-
 .../jakartawrappers/ServletInputStreamWrapper.java | 128 +++
 .../ServletOutputStreamWrapper.java                | 150 ++++
 .../ServletRegistrationWrapper.java                |  86 ++
 .../jakartawrappers/ServletRequestWrapper.java     | 381 +++++++++
 .../jakartawrappers/ServletResponseWrapper.java    | 145 ++++
 .../internal/jakartawrappers/ServletWrapper.java   |  98 +++
 .../SessionCookieConfigWrapper.java                | 107 +++
 .../WriteListenerWrapper.java}                     |  46 +-
 .../javaxwrappers/AsyncContextWrapper.java         | 104 +++
 .../javaxwrappers/AsyncListenerWrapper.java        |  78 ++
 .../base/internal/javaxwrappers/CookieWrapper.java | 111 +++
 .../internal/javaxwrappers/FilterChainWrapper.java |  51 ++
 .../javaxwrappers/FilterConfigWrapper.java         |  59 ++
 .../javaxwrappers/FilterRegistrationWrapper.java   | 115 +++
 .../javaxwrappers/HttpServletMappingWrapper.java   |  72 ++
 .../javaxwrappers/HttpServletRequestWrapper.java   | 264 ++++++
 .../javaxwrappers/HttpServletResponseWrapper.java  | 151 ++++
 .../javaxwrappers/HttpSessionContextWrapper.java   |  55 ++
 .../internal/javaxwrappers/HttpSessionWrapper.java | 130 +++
 .../base/internal/javaxwrappers/PartWrapper.java   |  91 ++
 .../internal/javaxwrappers/PushBuilderWrapper.java | 116 +++
 .../ReadListenerWrapper.java}                      |  60 +-
 .../javaxwrappers/RequestDispatcherWrapper.java    |  61 ++
 .../javaxwrappers/RuntimeServiceWrapper.java       | 371 ++++++++
 .../javaxwrappers/ServletConfigWrapper.java        |  59 ++
 .../javaxwrappers/ServletContextWrapper.java       | 416 +++++++++
 .../ServletExceptionUtil.java}                     |  45 +-
 .../ServletExceptionWrapper.java}                  |  44 +-
 .../javaxwrappers/ServletInputStreamWrapper.java   | 128 +++
 .../javaxwrappers/ServletOutputStreamWrapper.java  | 150 ++++
 .../javaxwrappers/ServletRegistrationWrapper.java  |  86 ++
 .../javaxwrappers/ServletRequestWrapper.java       | 377 ++++++++
 .../javaxwrappers/ServletResponseWrapper.java      | 145 ++++
 .../internal/javaxwrappers/ServletWrapper.java     |  83 ++
 .../javaxwrappers/SessionCookieConfigWrapper.java  | 107 +++
 .../WriteListenerWrapper.java}                     |  46 +-
 .../base/internal/registry/ErrorPageRegistry.java  |   8 +-
 .../internal/registry/EventListenerRegistry.java   |  34 +-
 .../base/internal/registry/FilterRegistry.java     |   8 +-
 .../base/internal/registry/HandlerRegistry.java    |   4 +-
 .../http/base/internal/registry/ListenerMap.java   |   4 +-
 .../base/internal/registry/PathResolution.java     |   2 +-
 .../internal/registry/PathResolverFactory.java     |   4 +-
 .../registry/PerContextHandlerRegistry.java        |   4 +-
 .../base/internal/registry/ServletRegistry.java    |  12 +-
 .../http/base/internal/runtime/AbstractInfo.java   |  29 +-
 .../http/base/internal/runtime/FilterInfo.java     |  35 +-
 .../http/base/internal/runtime/ListenerInfo.java   |  71 +-
 .../base/internal/runtime/PreprocessorInfo.java    |  26 +-
 .../http/base/internal/runtime/ResourceInfo.java   |  10 +-
 .../internal/runtime/ServletContextHelperInfo.java |  20 +-
 .../http/base/internal/runtime/ServletInfo.java    |  27 +-
 .../internal/runtime/WhiteboardServiceInfo.java    |   2 +-
 .../runtime/dto/BaseServletDTOBuilder.java         |   2 +-
 .../internal/runtime/dto/BuilderConstants.java     |  24 +-
 .../internal/runtime/dto/ErrorPageDTOBuilder.java  |   4 +-
 .../base/internal/runtime/dto/FailedDTOHolder.java |  14 +-
 .../internal/runtime/dto/FilterDTOBuilder.java     |   6 +-
 .../internal/runtime/dto/ListenerDTOBuilder.java   |   6 +-
 .../runtime/dto/PreprocessorDTOBuilder.java        |   4 +-
 .../base/internal/runtime/dto/RegistryRuntime.java |   4 +-
 .../runtime/dto/RequestInfoDTOBuilder.java         |   6 +-
 .../internal/runtime/dto/ResourceDTOBuilder.java   |   4 +-
 .../internal/runtime/dto/RuntimeDTOBuilder.java    |  20 +-
 .../runtime/dto/ServletContextDTOBuilder.java      |   6 +-
 .../internal/runtime/dto/ServletDTOBuilder.java    |   4 +-
 .../base/internal/service/DefaultHttpContext.java  |  14 +-
 .../HttpResourceServlet.java}                      |  29 +-
 .../base/internal/service/HttpServiceFactory.java  |  14 +-
 .../internal/service/HttpServiceRuntimeImpl.java   |  76 +-
 .../internal/service/PerBundleHttpServiceImpl.java |  49 +-
 .../base/internal/service/ServletContextImpl.java  |  53 +-
 .../internal/service/ServletContextManager.java    |   2 +-
 .../internal/service/SharedHttpServiceImpl.java    |  60 +-
 .../internal/whiteboard/FailureStateHandler.java   |  14 +-
 .../whiteboard/HttpServiceContextHandler.java      |   2 +-
 .../whiteboard/PerBundleServletContextImpl.java    |  53 +-
 .../whiteboard/RegistrationFailureException.java   |   2 +-
 .../{service => whiteboard}/ResourceServlet.java   |  91 +-
 .../whiteboard/SharedServletContextImpl.java       |  32 +-
 .../whiteboard/WhiteboardContextHandler.java       |  12 +-
 .../internal/whiteboard/WhiteboardManager.java     |  97 ++-
 .../internal/whiteboard/tracker/FilterTracker.java |   6 +-
 .../whiteboard/tracker/JavaxFilterTracker.java     |  88 ++
 .../whiteboard/tracker/JavaxListenersTracker.java  | 169 ++++
 .../tracker/JavaxPreprocessorTracker.java          |  82 ++
 ....java => JavaxServletContextHelperTracker.java} |  76 +-
 .../whiteboard/tracker/JavaxServletTracker.java    |  88 ++
 .../whiteboard/tracker/ListenersTracker.java       |  18 +-
 .../whiteboard/tracker/PreprocessorTracker.java    |   6 +-
 .../whiteboard/tracker/ResourceTracker.java        |   2 +-
 .../tracker/ServletContextHelperTracker.java       |   5 +-
 .../whiteboard/tracker/ServletTracker.java         |   6 +-
 .../whiteboard/HttpWhiteboardConstants.java        | 597 +++++++++++++
 .../service/servlet/whiteboard/Preprocessor.java   |  57 ++
 .../servlet/whiteboard/ServletContextHelper.java   | 331 ++++++++
 .../service/servlet/whiteboard/package-info.java   |  42 +
 .../whiteboard/runtime/HttpServiceRuntime.java     |  58 ++
 .../runtime/HttpServiceRuntimeConstants.java       |  68 ++
 .../whiteboard/runtime/dto/BaseServletDTO.java     |  76 ++
 .../whiteboard/runtime/dto/DTOConstants.java       | 115 +++
 .../whiteboard/runtime/dto/ErrorPageDTO.java       |  40 +
 .../whiteboard/runtime/dto/FailedErrorPageDTO.java |  46 +
 .../whiteboard/runtime/dto/FailedFilterDTO.java    |  46 +
 .../whiteboard/runtime/dto/FailedListenerDTO.java  |  46 +
 .../runtime/dto/FailedPreprocessorDTO.java         |  40 +
 .../whiteboard/runtime/dto/FailedResourceDTO.java  |  46 +
 .../runtime/dto/FailedServletContextDTO.java       |  53 ++
 .../whiteboard/runtime/dto/FailedServletDTO.java   |  48 ++
 .../servlet/whiteboard/runtime/dto/FilterDTO.java  | 102 +++
 .../whiteboard/runtime/dto/ListenerDTO.java        |  51 ++
 .../whiteboard/runtime/dto/PreprocessorDTO.java    |  53 ++
 .../whiteboard/runtime/dto/RequestInfoDTO.java     |  62 ++
 .../whiteboard/runtime/dto/ResourceDTO.java        |  59 ++
 .../servlet/whiteboard/runtime/dto/RuntimeDTO.java | 109 +++
 .../whiteboard/runtime/dto/ServletContextDTO.java  | 133 +++
 .../servlet/whiteboard/runtime/dto/ServletDTO.java |  81 ++
 .../whiteboard/runtime/dto/package-info.java       |  44 +
 .../servlet/whiteboard/runtime/package-info.java   |  44 +
 .../internal/context/ServletContextImplTest.java   |  46 +-
 .../context/ServletContextManagerTest.java         |   2 +-
 .../internal/handler/FilterConfigImplTest.java     |   2 +-
 .../base/internal/handler/FilterHandlerTest.java   |  22 +-
 .../handler/HttpServiceServletHandlerTest.java     |  20 +-
 .../internal/handler/HttpSessionWrapperTest.java   |   4 +-
 .../internal/handler/ServletConfigImplTest.java    |   2 +-
 .../internal/registry/ErrorPageRegistryTest.java   |  16 +-
 .../registry/EventListenerRegistryTest.java        |   8 +-
 .../base/internal/registry/FilterRegistryTest.java |  14 +-
 .../internal/registry/HandlerRegistryTest.java     |  16 +-
 .../internal/registry/PathResolverFactoryTest.java |   2 +-
 .../internal/registry/ServletRegistryTest.java     |  16 +-
 .../internal/runtime/AbstractInfoOrderingTest.java |   6 +
 .../base/internal/runtime/ListenerInfoTest.java    |   6 +-
 .../internal/service/HttpServiceFactoryTest.java   |   2 +-
 .../whiteboard/FailureStateHandlerTest.java        |   4 +-
 http/{bridge => bridge-4.x}/pom.xml                |   0
 .../main/appended-resources/META-INF/DEPENDENCIES  |  16 +
 .../src/main/appended-resources/META-INF/NOTICE    |   4 +
 .../http/bridge/internal/BridgeActivator.java      |   0
 http/bridge/pom.xml                                |  17 +-
 .../http/bridge/internal/BridgeActivator.java      |  12 +-
 http/itest/pom.xml                                 |  10 +-
 .../felix/http/itest/BaseIntegrationTest.java      |   1 +
 http/{jetty => jetty-4.x}/pom.xml                  |   0
 .../main/appended-resources/META-INF/DEPENDENCIES  |  20 +
 .../src/main/appended-resources/META-INF/NOTICE    |   8 +
 .../apache/felix/http/jetty/ConnectorFactory.java  |  59 ++
 .../http/jetty/LoadBalancerCustomizerFactory.java  |  47 +
 .../jetty/internal/ConfigMetaTypeProvider.java     | 644 ++++++++++++++
 .../jetty/internal/ConnectorFactoryTracker.java    |  89 ++
 .../http/jetty/internal/CustomizerWrapper.java}    |  42 +-
 .../felix/http/jetty/internal/FileRequestLog.java  |  97 +++
 .../ForwardedRequestCustomizerFactory.java}        |  36 +-
 .../felix/http/jetty/internal/JettyActivator.java  | 150 ++++
 .../felix/http/jetty/internal/JettyConfig.java     | 944 +++++++++++++++++++++
 .../felix/http/jetty/internal/JettyLogger.java     | 129 +++
 .../http/jetty/internal/JettyManagedService.java}  |  24 +-
 .../jetty/internal/JettyManagedServiceFactory.java | 101 +++
 .../felix/http/jetty/internal/JettyService.java    |   0
 .../http/jetty/internal/JettyServiceStarter.java   |  50 ++
 .../LoadBalancerCustomizerFactoryTracker.java      | 147 ++++
 .../http/jetty/internal/LogServiceRequestLog.java  |  74 ++
 .../http/jetty/internal/MBeanServerTracker.java    |  66 ++
 .../http/jetty/internal/RequestLogTracker.java     | 114 +++
 .../jetty/internal/webapp/WebAppBundleContext.java |   0
 .../jetty/internal/webapp/WebAppBundleTracker.java |   0
 .../felix/http/jetty/internal/webapp/WebEvent.java |   0
 .../org/apache/felix/http/jetty/package-info.java  |   0
 .../felix/http/jetty/internal/JettyConfigTest.java | 158 ++++
 .../http/jetty/internal/JettyServiceTest.java      |   0
 .../LoadBalancerCustomizerFactoryTrackerTest.java  | 236 ++++++
 .../http/jetty/internal/RequestLogTrackerTest.java |  98 +++
 http/jetty/pom.xml                                 |  43 +-
 .../felix/http/jetty/internal/JettyService.java    |   8 +-
 .../jetty/internal/webapp/WebAppBundleContext.java |   0
 .../jetty/internal/webapp/WebAppBundleTracker.java |   4 +-
 .../felix/http/jetty/internal/webapp/WebEvent.java |   0
 .../org/apache/felix/http/jetty/package-info.java  |   4 +-
 .../http/jetty/internal/JettyServiceTest.java      |  28 +-
 http/pom.xml                                       |   3 +
 340 files changed, 17231 insertions(+), 1116 deletions(-)

diff --git a/http/base/pom.xml b/http/base-4.x/pom.xml
similarity index 100%
copy from http/base/pom.xml
copy to http/base-4.x/pom.xml
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/AbstractActivator.java
similarity index 50%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/AbstractActivator.java
index 22a048d..f7a062b 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/AbstractActivator.java
@@ -14,40 +14,42 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.service;
+package org.apache.felix.http.base.internal;
 
-import org.osgi.service.http.HttpContext;
-import org.osgi.framework.Bundle;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.net.URL;
+import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
 
-public final class DefaultHttpContext 
-    implements HttpContext
+public abstract class AbstractActivator
+    implements BundleActivator
 {
-    private Bundle bundle;
+    private volatile BundleContext context;
 
-    public DefaultHttpContext(Bundle bundle)
+    protected final BundleContext getBundleContext()
     {
-        this.bundle = bundle;
+        return this.context;
     }
 
-    public String getMimeType(String name)
+    @Override
+    public final void start(final BundleContext context)
+        throws Exception
     {
-        return null;
+        this.context = context;
+        SystemLogger.init(context);
+        doStart();
     }
 
-    public URL getResource(String name)
+    @Override
+    public final void stop(final BundleContext context)
+        throws Exception
     {
-        if (name.startsWith("/")) {
-            name = name.substring(1);
-        }
-
-        return this.bundle.getResource(name);
+        doStop();
+        SystemLogger.destroy();
     }
 
-    public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res)
-    {
-        return true;
-    }
+    protected abstract void doStart()
+        throws Exception;
+
+    protected abstract void doStop()
+        throws Exception;
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/AbstractHttpActivator.java
similarity index 59%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/AbstractHttpActivator.java
index 3b210cd..937c7ad 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/AbstractHttpActivator.java
@@ -14,26 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.registry;
-
-import javax.servlet.http.MappingMatch;
-
-/**
- * Resolution of a servlet based on the path
- */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
-
-    public String[] patterns;
-
-    public String matchedPattern;
-
-    public MappingMatch match;
-
-    public String matchValue;
+package org.apache.felix.http.base.internal;
+
+public abstract class AbstractHttpActivator
+    extends AbstractActivator
+{
+    private HttpServiceController controller;
+
+    protected final HttpServiceController getHttpServiceController()
+    {
+        return this.controller;
+    }
+
+    @Override
+    protected void doStart()
+        throws Exception
+    {
+        this.controller = new HttpServiceController(getBundleContext());
+    }
+
+    @Override
+    protected void doStop()
+        throws Exception
+    {
+        this.controller.unregister();
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/HttpConfig.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/HttpConfig.java
new file mode 100644
index 0000000..150d39a
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/HttpConfig.java
@@ -0,0 +1,164 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+public class HttpConfig {
+
+    public static final String PROP_INVALIDATE_SESSION = "org.apache.felix.http.session.invalidate";
+
+    public static final boolean DEFAULT_INVALIDATE_SESSION = true;
+
+    public static final String PROP_UNIQUE_SESSION_ID = "org.apache.felix.http.session.uniqueid";
+
+    public static final boolean DEFAULT_UNIQUE_SESSION_ID = true;
+
+    private volatile boolean uniqueSessionId;
+
+    private volatile boolean invalidateContainerSession;
+
+    public static final String PROP_CONTAINER_ADDED_ATTRIBUTE = "org.apache.felix.http.session.container.attribute";
+
+    private volatile Set<String> containerAddedAttribueSet;
+
+    public boolean isUniqueSessionId() {
+        return uniqueSessionId;
+    }
+
+    public void setUniqueSessionId(boolean appendSessionId) {
+        this.uniqueSessionId = appendSessionId;
+    }
+
+    public boolean isInvalidateContainerSession() {
+        return invalidateContainerSession;
+    }
+
+    public void setInvalidateContainerSession(boolean invalidateContainerSession) {
+        this.invalidateContainerSession = invalidateContainerSession;
+    }
+
+    public Set<String> getContainerAddedAttribueSet() {
+        return containerAddedAttribueSet;
+    }
+
+    public void setContainerAddedAttribueSet(Set<String> containerAddedAttribueSet) {
+        this.containerAddedAttribueSet = containerAddedAttribueSet;
+    }
+
+
+    public void configure(@NotNull final Dictionary<String, Object> props) {
+        this.setUniqueSessionId(this.getBooleanProperty(props, PROP_UNIQUE_SESSION_ID, DEFAULT_UNIQUE_SESSION_ID));
+        this.setInvalidateContainerSession(this.getBooleanProperty(props, PROP_INVALIDATE_SESSION, DEFAULT_INVALIDATE_SESSION));
+        this.setContainerAddedAttribueSet(this.getStringSetProperty(props, PROP_CONTAINER_ADDED_ATTRIBUTE));
+    }
+
+
+    private boolean getBooleanProperty(final Dictionary<String, Object> props, final String name, final boolean defValue)
+    {
+        final Object v = props.get(name);
+        if ( v != null )
+        {
+            final String value = String.valueOf(v);
+            return "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value);
+        }
+
+        return defValue;
+    }
+
+
+    /**
+     * Get the property value as a string array.
+     * Empty values are filtered out - if the resulting array is empty
+     * the default value is returned.
+     */
+    private String[] getStringArrayProperty(final Dictionary<String, Object> props,String name, String[] defValue)
+    {
+        Object value = props.get(name);
+        if (value instanceof String)
+        {
+            final String stringVal = ((String) value).trim();
+            if (stringVal.length() > 0)
+            {
+                return stringVal.split(",");
+            }
+        }
+        else if (value instanceof String[])
+        {
+            final String[] stringArr = (String[]) value;
+            final List<String> list = new ArrayList<>();
+            for (final String stringVal : stringArr)
+            {
+                if (stringVal.trim().length() > 0)
+                {
+                    list.add(stringVal.trim());
+                }
+            }
+            if (list.size() > 0)
+            {
+                return list.toArray(new String[list.size()]);
+            }
+        }
+        else if (value instanceof Collection)
+        {
+            final ArrayList<String> conv = new ArrayList<>();
+            for (Iterator<?> vi = ((Collection<?>) value).iterator(); vi.hasNext();)
+            {
+                Object object = vi.next();
+                if (object != null)
+                {
+                    conv.add(String.valueOf(object));
+                }
+            }
+            if (conv.size() > 0)
+            {
+                return conv.toArray(new String[conv.size()]);
+            }
+        }
+        return defValue;
+    }
+
+    /**
+     * get Property values in set format,so that it can directly compare with remaining
+     * attributes of session.using set, as it will take O(1) time for searching.
+     * @param props
+     * @param name
+     * @return
+     */
+    private Set<String> getStringSetProperty(final Dictionary<String, Object> props,String name) {
+
+        String array[] = getStringArrayProperty(props,name,new String[0]) ;
+        Set<String> propertySet = new HashSet<>();
+
+        for(String property : array){
+
+            if(property != null && !"".equals(property.trim())){
+                propertySet.add(property);
+            }
+        }
+
+        return  propertySet;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/MultipartConfig.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/MultipartConfig.java
new file mode 100644
index 0000000..42e04ca
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/MultipartConfig.java
@@ -0,0 +1,76 @@
+/*
+ * 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.dispatch;
+
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+
+public final class MultipartConfig
+{
+    public static final MultipartConfig DEFAULT_CONFIG = new MultipartConfig(null, null, -1, -1);
+
+    public static final MultipartConfig INVALID_CONFIG = new MultipartConfig(null, null, -1, -1);
+
+    /**
+     * Specifies the multipart threshold
+     */
+    public final int multipartThreshold;
+
+    /**
+     * Specifies the multipart location
+     */
+    public final String multipartLocation;
+
+    /**
+     * Specifies the multipart max file size
+     */
+    public final long multipartMaxFileSize;
+
+    /**
+     * Specifies the multipart max request size
+     */
+    public final long multipartMaxRequestSize;
+
+    public MultipartConfig(final Integer threshold,
+            final String location,
+            final long maxFileSize,
+            final long maxRequestSize)
+    {
+        if ( threshold != null && threshold > 0)
+        {
+            this.multipartThreshold = threshold;
+        }
+        else
+        {
+            this.multipartThreshold = DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD;
+        }
+        this.multipartLocation = location;
+        if ( maxFileSize > 0 || maxFileSize == -1 ) {
+            this.multipartMaxFileSize = maxFileSize;
+        }
+        else
+        {
+            this.multipartMaxFileSize = -1;
+        }
+        if ( maxRequestSize > 0 || maxRequestSize == -1 ) {
+            this.multipartMaxRequestSize = maxRequestSize;
+        }
+        else
+        {
+            this.multipartMaxRequestSize = -1;
+        }
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/ConsoleLogger.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/ConsoleLogger.java
new file mode 100644
index 0000000..a669cec
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/ConsoleLogger.java
@@ -0,0 +1,81 @@
+/*
+ * 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.logger;
+
+import java.io.PrintStream;
+
+import org.osgi.service.log.LogService;
+
+public final class ConsoleLogger implements InternalLogger
+{
+    @Override
+    public void log(final int level, final String message, final Throwable ex)
+    {
+        if ( isLogEnabled(level) )
+        {
+            // output depending on level
+            final PrintStream out = ( level == LogService.LOG_ERROR )? System.err: System.out;
+
+            // level as a string
+            final StringBuilder buf = new StringBuilder();
+            switch (level)
+            {
+                case ( LogService.LOG_DEBUG ):
+                    buf.append( "[DEBUG] " );
+                    break;
+                case ( LogService.LOG_INFO ):
+                    buf.append( "[INFO] " );
+                    break;
+                case ( LogService.LOG_WARNING ):
+                    buf.append( "[WARN] " );
+                    break;
+                case ( LogService.LOG_ERROR ):
+                    buf.append( "[ERROR] " );
+                    break;
+                default:
+                    buf.append( "UNK  : " );
+                    break;
+            }
+
+            buf.append(message);
+
+            final String msg = buf.toString();
+
+            if ( ex == null )
+            {
+                out.println(msg);
+            }
+            else
+            {
+                // keep the message and the stacktrace together
+                synchronized ( out )
+                {
+                    out.println( msg );
+                    ex.printStackTrace( out );
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean isLogEnabled(final int level)
+    {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/http/jetty/src/main/java/org/apache/felix/http/jetty/package-info.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/InternalLogger.java
similarity index 51%
copy from http/jetty/src/main/java/org/apache/felix/http/jetty/package-info.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/InternalLogger.java
index 77d7dfe..d3fc9aa 100644
--- a/http/jetty/src/main/java/org/apache/felix/http/jetty/package-info.java
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/InternalLogger.java
@@ -1,22 +1,26 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
+ * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   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
+ * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
-@Version("2.1")
-package org.apache.felix.http.jetty;
+package org.apache.felix.http.base.internal.logger;
 
-import org.osgi.annotation.versioning.Version;
\ No newline at end of file
+interface InternalLogger {
+
+    void log(int level, String message, Throwable exception);
+
+    boolean isLogEnabled(int level);
+}
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/JDK14Logger.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/JDK14Logger.java
new file mode 100644
index 0000000..8e7f907
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/JDK14Logger.java
@@ -0,0 +1,74 @@
+/*
+ * 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.logger;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.service.log.LogService;
+
+/**
+ * Logger based on Java Logging API.
+ */
+public final class JDK14Logger implements InternalLogger
+{
+    private final Logger logger = Logger.getLogger("org.apache.felix.http");
+
+    private Level getLevel(final int level)
+    {
+        Level logLevel;
+        switch (level)
+        {
+            case LogService.LOG_DEBUG:
+                logLevel = Level.FINE;
+                break;
+            case LogService.LOG_INFO:
+                logLevel = Level.INFO;
+                break;
+            case LogService.LOG_WARNING:
+                logLevel = Level.WARNING;
+                break;
+            case LogService.LOG_ERROR:
+                logLevel = Level.SEVERE;
+                break;
+            default: logLevel = Level.FINE;
+        }
+        return logLevel;
+    }
+
+    @Override
+    public boolean isLogEnabled(final int level) {
+        return this.logger.isLoggable(getLevel(level));
+    }
+
+    @Override
+    public void log(final int level, final String message, final Throwable exception)
+    {
+        final Level logLevel = getLevel(level);
+
+        if (exception != null)
+        {
+            this.logger.log(logLevel, message, exception);
+        }
+        else
+        {
+            this.logger.log(logLevel, message);
+        }
+    }
+}
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/LogServiceEnabledLogger.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/LogServiceEnabledLogger.java
new file mode 100644
index 0000000..dc74510
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/LogServiceEnabledLogger.java
@@ -0,0 +1,158 @@
+/*
+ * 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.logger;
+
+import org.apache.felix.http.base.internal.util.ServiceUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * This abstract class adds support for using a LogService
+ */
+public class LogServiceEnabledLogger
+{
+    // name of the LogService class (this is a string to not create a reference to the class)
+    // With R7, LogService is deprecated but extends the newer LoggerFactory
+    private static final String LOGSERVICE_CLASS = "org.osgi.service.log.LogService";
+
+    private static final String JUL_LOGGER = "org.apache.felix.http.log.jul";
+
+    // the log service to log messages to
+    protected final ServiceTracker<Object, Object> logServiceTracker;
+
+    private volatile InternalLogger currentLogger;
+
+    protected volatile int trackingCount = -2;
+
+    private final InternalLogger defaultLogger;
+
+    public LogServiceEnabledLogger(final BundleContext bundleContext)
+    {
+        Object julLogOpt = bundleContext.getProperty(JUL_LOGGER);
+        if ( julLogOpt == null ) {
+            julLogOpt = System.getProperty(JUL_LOGGER);
+        }
+        if ( julLogOpt != null ) {
+            this.defaultLogger = new JDK14Logger();
+        } else {
+            this.defaultLogger = new ConsoleLogger();
+        }
+
+        // Start a tracker for the log service
+        // we only track a single log service which in reality should be enough
+        logServiceTracker = new ServiceTracker<>( bundleContext, LOGSERVICE_CLASS, new ServiceTrackerCustomizer<Object, Object>()
+        {
+            private volatile boolean hasService = false;
+
+            @Override
+            public Object addingService(final ServiceReference<Object> reference)
+            {
+                if ( !hasService )
+                {
+                    final Object logService = ServiceUtils.safeGetService(bundleContext, reference);
+                    if ( logService != null )
+                    {
+                        hasService = true;
+                        final LogServiceSupport lsl = new LogServiceSupport(logService);
+                        return lsl;
+                    }
+                }
+                return null;
+            }
+
+            @Override
+            public void modifiedService(final ServiceReference<Object> reference, final Object service)
+            {
+                // nothing to do
+            }
+
+            @Override
+            public void removedService(final ServiceReference<Object> reference, final Object service)
+            {
+                hasService = false;
+                ServiceUtils.safeUngetService(bundleContext, reference);
+            }
+        } );
+        logServiceTracker.open();
+    }
+
+    /**
+     * Close the logger
+     */
+    public void close()
+    {
+        // stop the tracker
+        logServiceTracker.close();
+    }
+
+    /**
+     * Returns {@code true} if logging for the given level is enabled.
+     */
+    public boolean isLogEnabled(final int level)
+    {
+        return getLogger().isLogEnabled(level);
+    }
+
+    /**
+     * Method to actually emit the log message. If the LogService is available,
+     * the message will be logged through the LogService. Otherwise the message
+     * is logged to stdout (or stderr in case of LOG_ERROR level messages),
+     *
+     * @param level The log level of the messages. This corresponds to the log
+     *          levels defined by the OSGi LogService.
+     * @param message The message to print
+     * @param ex The <code>Throwable</code> causing the message to be logged.
+     */
+    public void log(final int level, final String message, final Throwable ex)
+    {
+        if ( isLogEnabled( level ) )
+        {
+            getLogger().log(level, message, ex);
+        }
+    }
+
+    /**
+     * Get the internal logger
+     * @return The internal logger
+     */
+    InternalLogger getLogger()
+    {
+        if ( this.trackingCount < this.logServiceTracker.getTrackingCount() )
+        {
+            final Object logServiceSupport = this.logServiceTracker.getService();
+            if ( logServiceSupport == null )
+            {
+                this.currentLogger = this.getDefaultLogger();
+            }
+            else
+            {
+                this.currentLogger = ((LogServiceSupport)logServiceSupport).getLogger();
+            }
+            this.trackingCount = this.logServiceTracker.getTrackingCount();
+        }
+        return currentLogger;
+    }
+
+    InternalLogger getDefaultLogger()
+    {
+        return this.defaultLogger;
+    }
+}
\ No newline at end of file
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/LogServiceSupport.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/LogServiceSupport.java
new file mode 100644
index 0000000..a368185
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/LogServiceSupport.java
@@ -0,0 +1,40 @@
+/*
+ * 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.logger;
+
+import org.osgi.service.log.LogService;
+
+/**
+ * This is a logger based on the LogService.
+ */
+class LogServiceSupport
+{
+
+    private final LogService logService;
+
+    public LogServiceSupport(final Object logService)
+    {
+        this.logService = (LogService) logService;
+    }
+
+    InternalLogger getLogger()
+    {
+        return new R6LogServiceLogger(this.logService);
+    }
+}
\ No newline at end of file
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/R6LogServiceLogger.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/R6LogServiceLogger.java
new file mode 100644
index 0000000..f92303d
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/R6LogServiceLogger.java
@@ -0,0 +1,46 @@
+/*
+ * 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.logger;
+
+import org.osgi.service.log.LogService;
+
+/**
+ * This is a logger based on the R6 LogService.
+ */
+class R6LogServiceLogger implements InternalLogger
+{
+    private final LogService logService;
+
+    public R6LogServiceLogger(final LogService logService)
+    {
+        this.logService = logService;
+    }
+
+    @Override
+    public boolean isLogEnabled(final int level)
+    {
+        return true;
+    }
+
+    @Override
+    public void log(final int level, final String message, final Throwable ex)
+    {
+        this.logService.log(level, message, ex);
+    }
+}
\ No newline at end of file
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/SystemLogger.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/SystemLogger.java
new file mode 100644
index 0000000..ec70533
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/logger/SystemLogger.java
@@ -0,0 +1,161 @@
+/*
+ * 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.logger;
+
+import java.lang.reflect.Array;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+public final class SystemLogger
+{
+    private static volatile LogServiceEnabledLogger LOGGER;
+
+    public static void init(final BundleContext bundleContext) {
+        LOGGER = new LogServiceEnabledLogger(bundleContext);
+    }
+
+    public static void destroy() {
+        if ( LOGGER != null ) {
+            LOGGER.close();
+            LOGGER = null;
+        }
+    }
+
+    private static String getMessage(final ServiceReference<?> ref, final String message)
+    {
+        if ( ref == null )
+        {
+            return message;
+        }
+        final Bundle bundle = ref.getBundle();
+        final StringBuilder ib = new StringBuilder();
+        ib.append("[ServiceReference ");
+        ib.append(String.valueOf(ref.getProperty(Constants.SERVICE_ID)));
+        ib.append(" from bundle ");
+        if ( bundle == null )
+        {
+            ib.append("<uninstalled>");
+        }
+        else
+        {
+            ib.append(bundle.getBundleId());
+            if ( bundle.getSymbolicName() != null )
+            {
+                ib.append(" : ");
+                ib.append(bundle.getSymbolicName());
+                ib.append(":");
+                ib.append(bundle.getVersion());
+            }
+        }
+        ib.append(" ref=");
+        ib.append(ref);
+        ib.append(" properties={");
+        boolean first = true;
+        for(final String name : ref.getPropertyKeys())
+        {
+            if ( first )
+            {
+                first = false;
+            }
+            else
+            {
+                ib.append(", ");
+            }
+            final Object val = ref.getProperty(name);
+            ib.append(name);
+            ib.append("=");
+            if ( val.getClass().isArray() )
+            {
+                boolean fa = true;
+                ib.append('[');
+                for(int i=0;i<Array.getLength(val);i++)
+                {
+                    if ( fa )
+                    {
+                        fa = false;
+                    }
+                    else
+                    {
+                        ib.append(", ");
+                    }
+                    ib.append(Array.get(val, i));
+                }
+            ib.append(']');
+            }
+            else
+            {
+                ib.append(val);
+            }
+        }
+        ib.append("}] ");
+        ib.append(message);
+
+        return ib.toString();
+    }
+
+    private static void log(
+            final int level,
+            final ServiceReference<?> ref,
+            final String message,
+            final Throwable cause) {
+        final LogServiceEnabledLogger l = LOGGER;
+        if ( l != null ) {
+            l.log(level, getMessage(ref, message), cause);
+        }
+    }
+
+    public static void debug(final String message)
+    {
+        log(LogService.LOG_DEBUG, null, message, null);
+    }
+
+    public static void debug(final ServiceReference<?> ref,  final String message)
+    {
+        log(LogService.LOG_DEBUG, ref, message, null);
+    }
+
+    public static void debug(final String message, final Throwable cause)
+    {
+        log(LogService.LOG_DEBUG, null, message, cause);
+    }
+
+    public static void info(final String message)
+    {
+        log(LogService.LOG_INFO, null, message, null);
+    }
+
+    public static void warning(final String message, final Throwable cause)
+    {
+        log(LogService.LOG_WARNING, null, message, cause);
+    }
+
+    public static void error(final String message, final Throwable cause)
+    {
+        log(LogService.LOG_ERROR, null, message, cause);
+    }
+
+    public static void error(final ServiceReference<?> ref, final String message, final Throwable cause)
+    {
+        log(LogService.LOG_ERROR, ref, message, cause);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolver.java
similarity index 70%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolver.java
index 3b210cd..389de1d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolver.java
@@ -16,24 +16,18 @@
  */
 package org.apache.felix.http.base.internal.registry;
 
-import javax.servlet.http.MappingMatch;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
 
-/**
- * Resolution of a servlet based on the path
- */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
 
-    public String pathInfo;
+public interface PathResolver extends Comparable<PathResolver> {
 
-    public String requestURI;
+    PathResolution resolve(String uri);
 
-    public String[] patterns;
+    ServletHandler getServletHandler();
 
-    public String matchedPattern;
+    int getRanking();
 
-    public MappingMatch match;
+    int getOrdering();
 
-    public String matchValue;
+    String getPattern();
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolverFactory.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolverFactory.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolverFactory.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PathResolverFactory.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ServletResolution.java
similarity index 70%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ServletResolution.java
index 3b210cd..5729a8b 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/registry/ServletResolution.java
@@ -16,24 +16,11 @@
  */
 package org.apache.felix.http.base.internal.registry;
 
-import javax.servlet.http.MappingMatch;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
 
-/**
- * Resolution of a servlet based on the path
- */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
-
-    public String[] patterns;
-
-    public String matchedPattern;
+public class ServletResolution {
 
-    public MappingMatch match;
+    public ServletHandler handler;
 
-    public String matchValue;
+    public PerContextHandlerRegistry handlerRegistry;
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/PreprocessorInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/PreprocessorInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/PreprocessorInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/PreprocessorInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceInfo.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceInfo.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceInfo.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceInfo.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/PreprocessorDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/PreprocessorDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/PreprocessorDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/PreprocessorDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ResourceServlet.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/ResourceServlet.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/ResourceServlet.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/ResourceServlet.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/InternalIdFactory.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/InternalIdFactory.java
new file mode 100644
index 0000000..0ab73eb
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/InternalIdFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provides service ids for services not provided through the service registry.
+ * <p>
+ * All provided ids are unique negative {@code long}s.
+ */
+public enum InternalIdFactory
+{
+    INSTANCE;
+
+    /** -1 is reserved for the http service servlet context. */
+    private final AtomicLong idCounter = new AtomicLong(-1);
+
+    public long next()
+    {
+        return idCounter.decrementAndGet();
+    }
+}
\ No newline at end of file
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/MimeTypes.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/MimeTypes.java
new file mode 100644
index 0000000..3833fda
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/MimeTypes.java
@@ -0,0 +1,211 @@
+/*
+ * 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.util;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public final class MimeTypes
+{
+    private final static MimeTypes INSTANCE =
+            new MimeTypes();
+
+    private final Map<String, String> extMap;
+
+    private MimeTypes()
+    {
+        this.extMap = new HashMap<String, String>();
+        this.extMap.put("abs", "audio/x-mpeg");
+        this.extMap.put("ai", "application/postscript");
+        this.extMap.put("aif", "audio/x-aiff");
+        this.extMap.put("aifc", "audio/x-aiff");
+        this.extMap.put("aiff", "audio/x-aiff");
+        this.extMap.put("aim", "application/x-aim");
+        this.extMap.put("art", "image/x-jg");
+        this.extMap.put("asf", "video/x-ms-asf");
+        this.extMap.put("asx", "video/x-ms-asf");
+        this.extMap.put("au", "audio/basic");
+        this.extMap.put("avi", "video/x-msvideo");
+        this.extMap.put("avx", "video/x-rad-screenplay");
+        this.extMap.put("bcpio", "application/x-bcpio");
+        this.extMap.put("bin", "application/octet-stream");
+        this.extMap.put("bmp", "image/bmp");
+        this.extMap.put("body", "text/html");
+        this.extMap.put("cdf", "application/x-cdf");
+        this.extMap.put("cer", "application/x-x509-ca-cert");
+        this.extMap.put("class", "application/java");
+        this.extMap.put("cpio", "application/x-cpio");
+        this.extMap.put("csh", "application/x-csh");
+        this.extMap.put("css", "text/css");
+        this.extMap.put("dib", "image/bmp");
+        this.extMap.put("doc", "application/msword");
+        this.extMap.put("dtd", "application/xml-dtd");
+        this.extMap.put("dv", "video/x-dv");
+        this.extMap.put("dvi", "application/x-dvi");
+        this.extMap.put("eps", "application/postscript");
+        this.extMap.put("etx", "text/x-setext");
+        this.extMap.put("exe", "application/octet-stream");
+        this.extMap.put("gif", "image/gif");
+        this.extMap.put("gk", "application/octet-stream");
+        this.extMap.put("gtar", "application/x-gtar");
+        this.extMap.put("gz", "application/x-gzip");
+        this.extMap.put("hdf", "application/x-hdf");
+        this.extMap.put("hqx", "application/mac-binhex40");
+        this.extMap.put("htc", "text/x-component");
+        this.extMap.put("htm", "text/html");
+        this.extMap.put("html", "text/html");
+        this.extMap.put("hqx", "application/mac-binhex40");
+        this.extMap.put("ief", "image/ief");
+        this.extMap.put("jad", "text/vnd.sun.j2me.app-descriptor");
+        this.extMap.put("jar", "application/java-archive");
+        this.extMap.put("java", "text/plain");
+        this.extMap.put("jnlp", "application/x-java-jnlp-file");
+        this.extMap.put("jpe", "image/jpeg");
+        this.extMap.put("jpeg", "image/jpeg");
+        this.extMap.put("jpg", "image/jpeg");
+        this.extMap.put("js", "text/javascript");
+        this.extMap.put("kar", "audio/x-midi");
+        this.extMap.put("latex", "application/x-latex");
+        this.extMap.put("m3u", "audio/x-mpegurl");
+        this.extMap.put("mac", "image/x-macpaint");
+        this.extMap.put("man", "application/x-troff-man");
+        this.extMap.put("mathml", "application/mathml+xml");
+        this.extMap.put("me", "application/x-troff-me");
+        this.extMap.put("mid", "audio/x-midi");
+        this.extMap.put("midi", "audio/x-midi");
+        this.extMap.put("mif", "application/x-mif");
+        this.extMap.put("mov", "video/quicktime");
+        this.extMap.put("movie", "video/x-sgi-movie");
+        this.extMap.put("mp1", "audio/x-mpeg");
+        this.extMap.put("mp2", "audio/x-mpeg");
+        this.extMap.put("mp3", "audio/x-mpeg");
+        this.extMap.put("mpa", "audio/x-mpeg");
+        this.extMap.put("mpe", "video/mpeg");
+        this.extMap.put("mpeg", "video/mpeg");
+        this.extMap.put("mpega", "audio/x-mpeg");
+        this.extMap.put("mpg", "video/mpeg");
+        this.extMap.put("mpv2", "video/mpeg2");
+        this.extMap.put("ms", "application/x-wais-source");
+        this.extMap.put("nc", "application/x-netcdf");
+        this.extMap.put("oda", "application/oda");
+        this.extMap.put("ogg", "application/ogg");
+        this.extMap.put("pbm", "image/x-portable-bitmap");
+        this.extMap.put("pct", "image/pict");
+        this.extMap.put("pdf", "application/pdf");
+        this.extMap.put("pgm", "image/x-portable-graymap");
+        this.extMap.put("pic", "image/pict");
+        this.extMap.put("pict", "image/pict");
+        this.extMap.put("pls", "audio/x-scpls");
+        this.extMap.put("png", "image/png");
+        this.extMap.put("pnm", "image/x-portable-anymap");
+        this.extMap.put("pnt", "image/x-macpaint");
+        this.extMap.put("ppm", "image/x-portable-pixmap");
+        this.extMap.put("ppt", "application/powerpoint");
+        this.extMap.put("ps", "application/postscript");
+        this.extMap.put("psd", "image/x-photoshop");
+        this.extMap.put("qt", "video/quicktime");
+        this.extMap.put("qti", "image/x-quicktime");
+        this.extMap.put("qtif", "image/x-quicktime");
+        this.extMap.put("ras", "image/x-cmu-raster");
+        this.extMap.put("rdf", "application/rdf+xml");
+        this.extMap.put("rgb", "image/x-rgb");
+        this.extMap.put("rm", "application/vnd.rn-realmedia");
+        this.extMap.put("roff", "application/x-troff");
+        this.extMap.put("rtf", "application/rtf");
+        this.extMap.put("rtx", "text/richtext");
+        this.extMap.put("sh", "application/x-sh");
+        this.extMap.put("shar", "application/x-shar");
+        this.extMap.put("shtml", "text/x-server-parsed-html");
+        this.extMap.put("sit", "application/x-stuffit");
+        this.extMap.put("smf", "audio/x-midi");
+        this.extMap.put("snd", "audio/basic");
+        this.extMap.put("src", "application/x-wais-source");
+        this.extMap.put("sv4cpio", "application/x-sv4cpio");
+        this.extMap.put("sv4crc", "application/x-sv4crc");
+        this.extMap.put("svg", "image/svg+xml");
+        this.extMap.put("svgz", "image/svg+xml");
+        this.extMap.put("swf", "application/x-shockwave-flash");
+        this.extMap.put("t", "application/x-troff");
+        this.extMap.put("tar", "application/x-tar");
+        this.extMap.put("tcl", "application/x-tcl");
+        this.extMap.put("tex", "application/x-tex");
+        this.extMap.put("texi", "application/x-texinfo");
+        this.extMap.put("texinfo", "application/x-texinfo");
+        this.extMap.put("tif", "image/tiff");
+        this.extMap.put("tiff", "image/tiff");
+        this.extMap.put("tr", "application/x-troff");
+        this.extMap.put("tsv", "text/tab-separated-values");
+        this.extMap.put("txt", "text/plain");
+        this.extMap.put("ulw", "audio/basic");
+        this.extMap.put("ustar", "application/x-ustar");
+        this.extMap.put("xbm", "image/x-xbitmap");
+        this.extMap.put("xml", "text/xml");
+        this.extMap.put("xpm", "image/x-xpixmap");
+        this.extMap.put("xsl", "application/xml");
+        this.extMap.put("xslt", "application/xslt+xml");
+        this.extMap.put("xwd", "image/x-xwindowdump");
+        this.extMap.put("vsd", "application/x-visio");
+        this.extMap.put("vxml", "application/voicexml+xml");
+        this.extMap.put("wav", "audio/x-wav");
+        this.extMap.put("wbmp", "image/vnd.wap.wbmp");
+        this.extMap.put("wml", "text/vnd.wap.wml");
+        this.extMap.put("wmlc", "application/vnd.wap.wmlc");
+        this.extMap.put("wmls", "text/vnd.wap.wmls");
+        this.extMap.put("wmlscriptc", "application/vnd.wap.wmlscriptc");
+        this.extMap.put("wrl", "x-world/x-vrml");
+        this.extMap.put("xht", "application/xhtml+xml");
+        this.extMap.put("xhtml", "application/xhtml+xml");
+        this.extMap.put("xls", "application/vnd.ms-excel");
+        this.extMap.put("xul", "application/vnd.mozilla.xul+xml");
+        this.extMap.put("Z", "application/x-compress");
+        this.extMap.put("z", "application/x-compress");
+        this.extMap.put("zip", "application/zip");
+    }
+
+    public String getByFile(String file)
+    {
+        if (file == null) {
+            return null;
+        }
+
+        int dot = file.lastIndexOf(".");
+        if (dot < 0) {
+            return null;
+        }
+
+        String ext = file.substring(dot + 1);
+        if (ext.length() < 1) {
+            return null;
+        }
+
+        return getByExtension(ext);
+    }
+
+    public String getByExtension(String ext)
+    {
+        if (ext == null) {
+            return null;
+        }
+
+        return this.extMap.get(ext);
+    }
+
+    public static MimeTypes get()
+    {
+        return INSTANCE;
+    }
+}
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
new file mode 100644
index 0000000..d54f431
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
@@ -0,0 +1,144 @@
+/*
+ * 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.util;
+
+import java.util.StringTokenizer;
+
+/**
+ * Some convenience utilities to deal with path patterns.
+ */
+public abstract class PatternUtil
+{
+
+    /**
+     * Check for valid servlet pattern
+     * @param pattern The pattern
+     * @return {@code true} if its valid
+     */
+    public static boolean isValidPattern(final String pattern)
+    {
+        if ( pattern == null )
+        {
+            return false;
+        }
+        if ( pattern.indexOf("?") != -1 )
+        {
+            return false;
+        }
+        // default and root
+        if ( pattern.length() == 0 || pattern.equals("/") )
+        {
+            return true;
+        }
+        // extension
+        if ( pattern.startsWith("*.") )
+        {
+            return pattern.indexOf("/") == -1;
+        }
+        if ( !pattern.startsWith("/") )
+        {
+            return false;
+        }
+        final int pos = pattern.indexOf('*');
+        if ( pos != -1 && pos < pattern.length() - 1 )
+        {
+            return false;
+        }
+        if ( pos != -1 && pattern.charAt(pos - 1) != '/')
+        {
+            return false;
+        }
+        if ( pattern.charAt(pattern.length() - 1) == '/')
+        {
+            return false;
+        }
+        return true;
+    }
+
+    // check for valid symbolic name
+    public static boolean isValidSymbolicName(final String name)
+    {
+        if ( name == null || name.isEmpty() )
+        {
+            return false;
+        }
+        boolean valid = true;
+        boolean expectToken = false;
+        boolean done = false;
+        final StringTokenizer st = new StringTokenizer(name, ".", true);
+        while ( !done && st.hasMoreTokens() )
+        {
+            final String token = st.nextToken();
+            if ( expectToken )
+            {
+                if ( !".".equals(token) )
+                {
+                    valid = false;
+                    done = true;
+                }
+                else
+                {
+                    expectToken = false;
+                }
+            }
+            else
+            {
+                if ( ".".equals(token) )
+                {
+                    valid = false;
+                    done = true;
+                }
+                else
+                {
+                    int i = 0;
+                    while ( i < token.length() && valid )
+                    {
+                        final char c = token.charAt(i);
+                        i++;
+                        if ( c >= 'a' && c <= 'z' )
+                        {
+                            continue;
+                        }
+                        if ( c >= 'A' && c <= 'Z' )
+                        {
+                            continue;
+                        }
+                        if ( c >= '0' && c <= '9' )
+                        {
+                            continue;
+                        }
+                        if ( c == '-' || c == '_' )
+                        {
+                            continue;
+                        }
+                        valid = false;
+                        done = true;
+                    }
+                }
+                expectToken = true;
+            }
+        }
+        if ( !expectToken )
+        {
+            valid = false;
+        }
+
+        return valid;
+    }
+}
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/ServiceUtils.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/ServiceUtils.java
new file mode 100644
index 0000000..3cb8b24
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/ServiceUtils.java
@@ -0,0 +1,89 @@
+/*
+ * 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.util;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Utility methods to get/unget services, ignoring exceptions that might occur
+ * on bundle stop/update
+ */
+public abstract class ServiceUtils {
+
+    /**
+     * Get the service
+     * @return The service or {@code null}
+     */
+    public static <T> T safeGetService(final BundleContext ctx, final ServiceReference<T> ref) {
+        try {
+            return ctx.getService(ref);
+        } catch ( final IllegalStateException | IllegalArgumentException | ServiceException ignore ) {
+            // ignore this
+        }
+        return null;
+    }
+
+    /**
+     * Unget the service
+     */
+    public static <T> void safeUngetService(final BundleContext ctx, final ServiceReference<T> ref) {
+        try {
+            ctx.ungetService(ref);
+        } catch ( final IllegalStateException | IllegalArgumentException | ServiceException ignore ) {
+            // ignore this
+        }
+    }
+
+    /**
+     * Get the service using {@code ServiceObjects}
+     * @return The service or {@code null}
+     */
+    public static <T> T safeGetServiceObjects(final BundleContext ctx, final ServiceReference<T> ref) {
+        if ( ctx != null ) {
+            try {
+                final ServiceObjects<T> so = ctx.getServiceObjects(ref);
+
+                return so == null ? null : so.getService();
+            } catch ( final IllegalStateException | IllegalArgumentException | ServiceException ignore ) {
+                // ignore this
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Unget the service using {@code ServiceObjects}
+     */
+    public static <T> void safeUngetServiceObjects(final BundleContext ctx, final ServiceReference<T> ref, final T service) {
+        if ( ctx != null && service != null ) {
+            try {
+                final ServiceObjects<T> so = ctx.getServiceObjects(ref);
+
+                if ( so != null ) {
+                    so.ungetService(service);
+                }
+            } catch ( final IllegalStateException | IllegalArgumentException | ServiceException ignore ) {
+                // ignore this
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
new file mode 100644
index 0000000..3c12958
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
@@ -0,0 +1,368 @@
+/*
+ * 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.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Some convenience methods for handling URI(-parts).
+ */
+public abstract class UriUtils
+{
+    private static final String SLASH_STR = "/";
+    private static final char DOT = '.';
+    private static final char SLASH = '/';
+
+    /**
+     * Concatenates two paths keeping their respective path-parts into consideration.
+     *
+     * @param path1 the first part of the path, can be <code>null</code>;
+     * @param path2 the second part of the path, can be <code>null</code>.
+     * @return the concatenated path, can be <code>null</code> in case both given arguments were <code>null</code>.
+     */
+    public static String concat(String path1, String path2)
+    {
+        // Handle special cases...
+        if (path1 == null && path2 == null)
+        {
+            return null;
+        }
+        if (path1 == null)
+        {
+            path1 = "";
+        }
+        if (path2 == null)
+        {
+            path2 = "";
+        }
+        if (isEmpty(path1) && isEmpty(path2))
+        {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        int idx = path1.indexOf('?');
+        if (idx == 0)
+        {
+            // path1 only consists of a query, append it to the second path...
+            return path2.concat(path1);
+        }
+        else if (idx > 0)
+        {
+            // path1 contains of a path + query, append the path first...
+            sb.append(path1.substring(0, idx));
+        }
+        else
+        {
+            // Plain paths...
+            sb.append(path1);
+            // need a slash?
+        }
+
+        if (endsWith(sb, SLASH_STR))
+        {
+            if (path2.startsWith(SLASH_STR))
+            {
+                sb.append(path2.substring(1));
+            }
+            else
+            {
+                sb.append(path2);
+            }
+        }
+        else
+        {
+            if (path2.startsWith(SLASH_STR))
+            {
+                sb.append(path2);
+            }
+            else if (sb.length() > 0 && !isEmpty(path2))
+            {
+                sb.append(SLASH_STR).append(path2);
+            }
+            else
+            {
+                sb.append(path2);
+            }
+        }
+
+        if (idx > 0)
+        {
+            // Add the query of path1...
+            sb.append(path1.substring(idx, path1.length()));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Decodes a given URL-encoded path assuming it is UTF-8 encoded.
+     *
+     * @param path the URL-encoded path, can be <code>null</code>.
+     * @return the decoded path, can be <code>null</code> only if the given path was <code>null</code>.
+     */
+    public static String decodePath(String path)
+    {
+        return decodePath(path, "UTF-8");
+    }
+
+    /**
+     * Decodes a given URL-encoded path using a given character encoding.
+     *
+     * @param path the URL-encoded path, can be <code>null</code>;
+     * @param encoding the character encoding to use, cannot be <code>null</code>.
+     * @return the decoded path, can be <code>null</code> only if the given path was <code>null</code>.
+     */
+    private static String decodePath(String path, String encoding)
+    {
+        // Special cases...
+        if (path == null)
+        {
+            return null;
+        }
+
+        CharsetDecoder decoder = Charset.forName(encoding).newDecoder();
+        decoder.onMalformedInput(CodingErrorAction.REPORT);
+        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+
+        int len = path.length();
+        ByteBuffer buf = ByteBuffer.allocate(len);
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < len; i++)
+        {
+            char ch = path.charAt(i);
+            if (ch == '%' && (i + 2 < len))
+            {
+                // URL-encoded char...
+                buf.put((byte) ((16 * hexVal(path, ++i)) + hexVal(path, ++i)));
+            }
+            else
+            {
+                if (buf.position() > 0)
+                {
+                    // flush encoded chars first...
+                    sb.append(decode(buf, decoder));
+                    buf.clear();
+                }
+
+                sb.append(ch);
+            }
+        }
+
+        // flush trailing encoded characters...
+        if (buf.position() > 0)
+        {
+            sb.append(decode(buf, decoder));
+            buf.clear();
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Removes all superfluous dot-segments using the algorithm described in RFC-3986 section 5.2.4.
+     *
+     * @param path the path to remove all dot-segments from, can be <code>null</code>.
+     * @return the cleaned path, can be <code>null</code> only if the given path was <code>null</code>.
+     */
+    public static String removeDotSegments(String path)
+    {
+        // Handle special cases...
+        if (path == null)
+        {
+            return null;
+        }
+        if (isEmpty(path))
+        {
+            return "";
+        }
+
+        StringBuilder scratch = new StringBuilder(path);
+        StringBuilder sb = new StringBuilder();
+        char l, la = 0, laa = 0, laaa = 0;
+
+        while (scratch.length() > 0)
+        {
+            l = la(scratch, 0);
+            la = la(scratch, 1);
+            laa = la(scratch, 2);
+
+            if (l == DOT)
+            {
+                if (la == 0)
+                {
+                    // (D) found '.' at the end of the URL
+                    break;
+                }
+                else if (la == DOT && laa == SLASH)
+                {
+                    // (A) found '../', remove it from the input...
+                    scratch.delete(0, 3);
+                    continue;
+                }
+                else if (la == DOT && laa == 0)
+                {
+                    // (D) found '..' at the end of the URL
+                    break;
+                }
+                else if (la == SLASH)
+                {
+                    // (A) found './', remove it from the input...
+                    scratch.delete(0, 2);
+                    continue;
+                }
+            }
+            else if (l == SLASH && la == DOT)
+            {
+                if (laa == SLASH)
+                {
+                    // (B) found '/./', remove the leading '/.'...
+                    scratch.delete(0, 2);
+                    continue;
+                }
+                else if (laa == 0)
+                {
+                    // (B) found '/.' as last part of the URL
+                    sb.append(SLASH);
+                    // we're done...
+                    break;
+                }
+                else if (laa == DOT)
+                {
+                    laaa = la(scratch, 3);
+                    if (laaa == SLASH)
+                    {
+                        // (C) found '/../', remove the '/..' part from the input...
+                        scratch.delete(0, 3);
+
+                        // go back one segment in the output, including the last '/'...
+                        sb.setLength(lb(sb, 0));
+                        continue;
+                    }
+                    else if (laaa == 0)
+                    {
+                        // (C) found '/..' as last part of the URL, go back one segment in the output, excluding the last '/'...
+                        sb.setLength(lb(sb, -1));
+                        // we're done...
+                        break;
+                    }
+                }
+            }
+
+            // (E) Copy everything up to (but not including) the next '/'...
+            do
+            {
+                sb.append(l);
+                scratch.delete(0, 1);
+                l = la(scratch, 0);
+            }
+            while (l != SLASH && l != 0);
+        }
+
+        return sb.toString();
+    }
+
+    private static char la(CharSequence sb, int idx)
+    {
+        if (sb.length() > idx)
+        {
+            return sb.charAt(idx);
+        }
+        return 0;
+    }
+
+    private static int lb(CharSequence sb, int offset)
+    {
+        int pos = sb.length() - 1 - offset;
+        while (pos > 0 && sb.charAt(pos + offset) != SLASH)
+        {
+            pos--;
+        }
+        return pos;
+    }
+
+    private static String decode(ByteBuffer bb, CharsetDecoder decoder)
+    {
+        CharBuffer cb = CharBuffer.allocate(128);
+
+        CoderResult result = decoder.decode((ByteBuffer) bb.flip(), cb, true /* endOfInput */);
+        if (result.isError())
+        {
+            throw new IllegalArgumentException("Malformed UTF-8!");
+        }
+
+        return ((CharBuffer) cb.flip()).toString();
+    }
+
+    private static boolean endsWith(CharSequence seq, String part)
+    {
+        int len = part.length();
+        if (seq.length() < len)
+        {
+            return false;
+        }
+        for (int i = 0; i < len; i++)
+        {
+            if (seq.charAt(seq.length() - (i + 1)) != part.charAt(i))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static int hexVal(CharSequence seq, int idx)
+    {
+        char ch = seq.charAt(idx);
+        if (ch >= '0' && ch <= '9')
+        {
+            return ch - '0';
+        }
+        else if (ch >= 'a' && ch <= 'f')
+        {
+            return 10 + (ch - 'a');
+        }
+        else if (ch >= 'A' && ch <= 'F')
+        {
+            return 10 + (ch - 'A');
+        }
+        throw new IllegalArgumentException("Invalid hex digit: " + ch);
+    }
+
+    private static boolean isEmpty(String value)
+    {
+        return value == null || "".equals(value.trim());
+    }
+
+    /**
+     * Creates a new {@link UriUtils} instance.
+     */
+    private UriUtils()
+    {
+        // Nop
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ListenersTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ListenersTracker.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ListenersTracker.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ListenersTracker.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/PreprocessorTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/PreprocessorTracker.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/PreprocessorTracker.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/PreprocessorTracker.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java
similarity index 100%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java
copy to http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java
diff --git a/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
new file mode 100644
index 0000000..d673d23
--- /dev/null
+++ b/http/base-4.x/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
@@ -0,0 +1,125 @@
+/*
+ * 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 java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Service tracker for all whiteboard services except servlet context helper.
+ * This tracker does not get/unget the service objects itself, but just forwards the service reference
+ * by creating an info data object. Each sub class creates a different
+ * data object.
+ */
+public abstract class WhiteboardServiceTracker<T> extends ServiceTracker<T, ServiceReference<T>>
+{
+    /** Map containing all info objects reported from the trackers. */
+    private final Map<Long, WhiteboardServiceInfo<T>> allInfos = new ConcurrentHashMap<Long, WhiteboardServiceInfo<T>>();
+
+    private static org.osgi.framework.Filter createFilter(final BundleContext btx, final String expr)
+    {
+        try
+        {
+            return btx.createFilter(expr);
+        }
+        catch ( final InvalidSyntaxException ise)
+        {
+            // we can safely ignore it as the filter is a constant
+        }
+        return null; // we never get here - and if we get an NPE which is fine
+    }
+
+    /** The  manager is called for each added/removed reference. */
+    private final WhiteboardManager contextManager;
+
+    /**
+     * Create a new tracker
+     * @param contextManager The context manager
+     * @param bundleContext The bundle context.
+     * @param filterExpr The filter expression for the services to track
+     */
+    public WhiteboardServiceTracker(final WhiteboardManager contextManager,
+            final BundleContext bundleContext, final String filterExpr)
+    {
+        super(bundleContext, createFilter(bundleContext, filterExpr), null);
+        this.contextManager = contextManager;
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        this.allInfos.clear();
+    }
+
+    @Override
+    public final ServiceReference<T> addingService(final ServiceReference<T> ref)
+    {
+        this.added(ref);
+        return ref;
+    }
+
+    @Override
+    public final void modifiedService(final ServiceReference<T> ref, final ServiceReference<T> service)
+    {
+        this.modified(ref);
+    }
+
+    @Override
+    public final void removedService(final ServiceReference<T> ref, final ServiceReference<T> service)
+    {
+        this.removed(ref);
+    }
+
+    private void modified(final ServiceReference<T> ref)
+    {
+        removed(ref);
+        added(ref);
+    }
+
+    private void added(final ServiceReference<T> ref)
+    {
+        final WhiteboardServiceInfo<T> info = this.getServiceInfo(ref);
+        if ( this.contextManager.addWhiteboardService(info) )
+        {
+            this.allInfos.put((Long)ref.getProperty(Constants.SERVICE_ID), info);
+        }
+    }
+
+    private void removed(final ServiceReference<T> ref)
+    {
+        final WhiteboardServiceInfo<T> info = this.allInfos.remove(ref.getProperty(Constants.SERVICE_ID));
+        if ( info != null )
+        {
+            this.contextManager.removeWhiteboardService(info);
+        }
+    }
+
+    /**
+     * Implemented by sub classes to create the correct whiteboard service info object.
+     * @param ref The service reference
+     * @return A whiteboard service info
+     */
+    protected abstract WhiteboardServiceInfo<T> getServiceInfo(final ServiceReference<T> ref);
+}
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterConfigImplTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/FilterConfigImplTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterConfigImplTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/FilterConfigImplTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapperTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapperTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapperTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapperTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/ServletConfigImplTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/ServletConfigImplTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/handler/ServletConfigImplTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/handler/ServletConfigImplTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/EventListenerRegistryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/EventListenerRegistryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/registry/EventListenerRegistryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/EventListenerRegistryTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/FilterRegistryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/FilterRegistryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/registry/FilterRegistryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/FilterRegistryTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/PathResolverFactoryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/PathResolverFactoryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/registry/PathResolverFactoryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/PathResolverFactoryTest.java
diff --git a/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistryTest.java
new file mode 100644
index 0000000..2733487
--- /dev/null
+++ b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistryTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.registry;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.felix.http.base.internal.HttpConfig;
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.junit.Test;
+
+/**
+ * Test for the ordering of servlet contexts
+ */
+public class PerContextHandlerRegistryTest
+{
+
+    @Test
+    public void testPathOrdering()
+    {
+        final List<PerContextHandlerRegistry> list = new ArrayList<>();
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0), new HttpConfig()));
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/foo", 2L, 0), new HttpConfig()));
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 3L, 0), new HttpConfig()));
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/bar", 4L, 0), new HttpConfig()));
+
+        Collections.sort(list);
+
+        assertEquals(2L, list.get(0).getContextServiceId());
+        assertEquals(4L, list.get(1).getContextServiceId());
+        assertEquals(1L, list.get(2).getContextServiceId());
+        assertEquals(3L, list.get(3).getContextServiceId());
+    }
+
+    @Test
+    public void testRankingOrdering()
+    {
+        final List<PerContextHandlerRegistry> list = new ArrayList<>();
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0), new HttpConfig()));
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 2L, 0), new HttpConfig()));
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 3L, -30), new HttpConfig()));
+        list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 4L, 50), new HttpConfig()));
+
+        Collections.sort(list);
+
+        assertEquals(4L, list.get(0).getContextServiceId());
+        assertEquals(1L, list.get(1).getContextServiceId());
+        assertEquals(2L, list.get(2).getContextServiceId());
+        assertEquals(3L, list.get(3).getContextServiceId());
+    }
+
+    @Test
+    public void testOrderingSymetry()
+    {
+        testSymetry("/", "/foo", 1L, 2L, 0, 0);
+        testSymetry("/", "/", 1L, 2L, 0, 10);
+        testSymetry("/", "/", 1L, 2L, 0, 0);
+        testSymetry("/", "/", 1L, -2L, 0, 0);
+        testSymetry("/", "/", -1L, -2L, 0, 0);
+        testSymetry("/", "/", 0L, -1L, 0, 0);
+        testSymetry("/", "/", 0L, 1L, 0, 0);
+    }
+
+    private void testSymetry(String path, String otherPath, long id, long otherId, int ranking, int otherRanking)
+    {
+        PerContextHandlerRegistry handlerRegistry = new PerContextHandlerRegistry(createServletContextHelperInfo(path, id, ranking), new HttpConfig());
+        PerContextHandlerRegistry other = new PerContextHandlerRegistry(createServletContextHelperInfo(otherPath, otherId, otherRanking), new HttpConfig());
+
+        assertEquals(handlerRegistry.compareTo(other), -other.compareTo(handlerRegistry));
+    }
+
+    @Test
+    public void testOrderingTransitivity()
+    {
+        testTransitivity("/", "/foo", "/barrr", 1L, 2L, 3L, 0, 0, 0);
+        testTransitivity("/", "/", "/", 1L, 2L, 3L, 1, 2, 3);
+        testTransitivity("/", "/", "/", 2L, 1L, 0L, 1, 2, 3);
+        testTransitivity("/", "/", "/", 2L, 1L, 0L, 0, 0, 0);
+        testTransitivity("/", "/", "/", 1L, -1L, 0L, 0, 0, 0);
+        testTransitivity("/", "/", "/", -2L, -1L, 0L, 0, 0, 0);
+    }
+
+    private void testTransitivity(String highPath, String midPath, String lowPath, long highId, long midId, long lowId, int highRanking, int midRanking, int lowRanking)
+    {
+        PerContextHandlerRegistry high = new PerContextHandlerRegistry(createServletContextHelperInfo(highPath, highId, highRanking), new HttpConfig());
+        PerContextHandlerRegistry mid = new PerContextHandlerRegistry(createServletContextHelperInfo(midPath, midId, midRanking), new HttpConfig());
+        PerContextHandlerRegistry low = new PerContextHandlerRegistry(createServletContextHelperInfo(lowPath, lowId, lowRanking), new HttpConfig());
+
+        assertTrue(high.compareTo(mid) > 0);
+        assertTrue(mid.compareTo(low) > 0);
+        assertTrue(high.compareTo(low) > 0);
+    }
+
+    private ServletContextHelperInfo createServletContextHelperInfo(final String path, final long serviceId, final int ranking)
+    {
+        return new ServletContextHelperInfo(ranking, serviceId, "", path, null);
+    }
+}
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/AbstractInfoOrderingTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/AbstractInfoOrderingTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/runtime/AbstractInfoOrderingTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/AbstractInfoOrderingTest.java
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/ListenerInfoTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/ListenerInfoTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/runtime/ListenerInfoTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/ListenerInfoTest.java
diff --git a/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java
new file mode 100644
index 0000000..ce77e42
--- /dev/null
+++ b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java
@@ -0,0 +1,734 @@
+/*
+ * 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.dto;
+
+
+//@RunWith(MockitoJUnitRunner.class)
+public class RuntimeDTOBuilderTest
+{
+/*
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    private static final Long ID_0 = -ID_COUNTER.incrementAndGet();
+    private static final Long ID_A = ID_COUNTER.incrementAndGet();
+    private static final Long ID_B = ID_COUNTER.incrementAndGet();
+    private static final Long ID_C = ID_COUNTER.incrementAndGet();
+    private static final Long ID_D = ID_COUNTER.incrementAndGet();
+
+    private static final Long ID_LISTENER_1 = ID_COUNTER.incrementAndGet();
+    private static final Long ID_LISTENER_2 = ID_COUNTER.incrementAndGet();
+
+    private static final List<String> CONTEXT_NAMES = Arrays.asList("0", "A", "B");
+
+    @SuppressWarnings("serial")
+    private static final Map<String, List<String>> CONTEXT_ENTITY_NAMES = new HashMap<String, List<String>>()
+            {
+                {
+                    put("0", Arrays.asList("1"));
+                    put("A", Arrays.asList("A_1"));
+                    put("B", Arrays.asList("B_1", "B_2"));
+                }
+            };
+
+    @SuppressWarnings("serial")
+    private static final Map<String, Object> RUNTIME_ATTRIBUTES = new HashMap<String, Object>()
+    {
+        {
+            put("attr_1", "val_1");
+            put("attr_2", "val_2");
+        }
+    };
+
+    @Mock private Bundle bundle;
+
+    @Mock private DTO testDTO;
+
+    @Mock private ExtServletContext context_0;
+    @Mock private ExtServletContext context_A;
+    @Mock private ExtServletContext context_B;
+    @Mock private ExtServletContext context_C;
+    @Mock private ExtServletContext context_D;
+
+    @Mock private ServiceReference<?> listener_1;
+    @Mock private ServiceReference<?> listener_2;
+
+    @Mock private ServiceReference<Object> resource;
+
+    @Mock private ServiceReference<HttpServiceRuntime> runtimeReference;
+
+    private RegistryRuntime registry;
+    private Map<String, Object> runtimeAttributes;
+
+    @Before
+    public void setUp()
+    {
+        registry = null;
+        runtimeAttributes = RUNTIME_ATTRIBUTES;
+        when(bundle.getBundleId()).thenReturn(47L);
+        when(runtimeReference.getBundle()).thenReturn(bundle);
+        when(runtimeReference.getUsingBundles()).thenReturn(null);
+        when(runtimeReference.getPropertyKeys()).thenReturn(runtimeAttributes.keySet().toArray(new String[5]));
+        for(final String key : runtimeAttributes.keySet())
+        {
+            when(runtimeReference.getProperty(key)).thenReturn(runtimeAttributes.get(key));
+        }
+        when(runtimeReference.getProperty(Constants.SERVICE_ID)).thenReturn(39L);
+    }
+
+    public ServletContextHelperRuntime setupContext(ServletContext context, String name, long serviceId)
+    {
+        when(context.getServletContextName()).thenReturn(name);
+
+        String path = "/" + name;
+        when(context.getContextPath()).thenReturn(path);
+
+        List<String> initParameterNames = asList("param_1", "param_2");
+        when(context.getInitParameterNames()).thenReturn(Collections.enumeration(initParameterNames));
+        when(context.getInitParameter("param_1")).thenReturn("init_val_1");
+        when(context.getInitParameter("param_2")).thenReturn("init_val_2");
+
+        Map<String, String> initParameters = createInitParameterMap();
+        ServletContextHelperInfo contextInfo = createContextInfo(0, serviceId, name, path, initParameters);
+
+        ContextHandler contextHandler = new ContextHandler(contextInfo, context, bundle);
+        PerContextEventListener eventListener = contextHandler.getListenerRegistry();
+
+        ServletContext sharedContext = contextHandler.getSharedContext();
+        sharedContext.setAttribute("intAttr", 1);
+        sharedContext.setAttribute("dateAttr", new Date());
+        sharedContext.setAttribute("stringAttr", "one");
+        sharedContext.setAttribute("dtoAttr", testDTO);
+
+        // TODO
+        return null;
+//        return contextHandler;
+    }
+
+    private Map<String, String> createInitParameterMap()
+    {
+        Map<String, String> initParameters = new HashMap<String, String>();
+        initParameters.put("param_1", "init_val_1");
+        initParameters.put("param_2", "init_val_2");
+        return initParameters;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Map<Long, Collection<ServiceReference<?>>> setupListeners()
+    {
+        Map<Long, Collection<ServiceReference<?>>> listenerRuntimes = new HashMap<Long, Collection<ServiceReference<?>>>();
+
+        listenerRuntimes.put(ID_0, asList(listener_1, listener_2));
+        listenerRuntimes.put(ID_A, Arrays.<ServiceReference<?>>asList(listener_1));
+        listenerRuntimes.put(ID_B, asList(listener_1, listener_2));
+
+        when(listener_1.getProperty(Constants.SERVICE_ID)).thenReturn(ID_LISTENER_1);
+        when(listener_1.getProperty(Constants.OBJECTCLASS))
+                .thenReturn(new String[] { "org.test.interface_1" });
+
+        when(listener_2.getProperty(Constants.SERVICE_ID)).thenReturn(ID_LISTENER_2);
+        when(listener_2.getProperty(Constants.OBJECTCLASS))
+                .thenReturn(new String[] { "org.test.interface_1", "org.test.interface_2" });
+
+        return listenerRuntimes;
+    }
+
+    public void setupResource()
+    {
+        when(resource.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN)).thenReturn(new String[] { "/" });
+        when(resource.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX)).thenReturn("prefix");
+    }
+
+    @Test
+    public void buildRuntimeDTO()
+    {
+        ServletContextHelperRuntime contextHelper_0 = setupContext(context_0, "0", ID_0);
+        ServletContextHelperRuntime contextHelper_A = setupContext(context_A, "A", ID_A);
+        ServletContextHelperRuntime contextHelper_B = setupContext(context_B, "B", ID_B);
+
+        List<ServletHandler> servlets = new ArrayList<ServletHandler>();
+        List<ServletHandler> resources = new ArrayList<ServletHandler>();
+
+        servlets.add(createTestServlet("1", context_0, ID_0));
+        resources.add(createTestServlet("1", context_0, ID_0));
+        List<FilterHandler> filters_0 = asList(createTestFilter("1", context_0));
+        List<ServletState> errorPages_0 = asList(createErrorPage("E_1", context_0, ID_0));
+        ContextRuntime contextRuntime_0 = new ContextRuntime(null, errorPages_0, null, null);
+
+        servlets.add(createTestServlet("A_1", context_A, ID_A));
+        resources.add(createTestServlet("A_1", context_A, ID_A));
+        List<FilterHandler> filters_A = asList(createTestFilter("A_1", context_A));
+        List<ServletState> errorPages_A = asList(createErrorPage("E_A_1", context_A, ID_A));
+        ContextRuntime contextRuntime_A = new ContextRuntime(null, errorPages_A, null, null);
+
+        servlets.addAll(asList(createTestServletWithServiceId("B_1", context_B, ID_B),
+                createTestServletWithServiceId("B_2", context_B, ID_B)));
+        resources.addAll(asList(createTestServletWithServiceId("B_1", context_B, ID_B),
+            createTestServletWithServiceId("B_2", context_B, ID_B)));
+        List<FilterHandler> filters_B = asList(createTestFilterWithServiceId("B_1", context_B),
+                createTestFilterWithServiceId("B_2", context_B));
+        List<ServletState> errorPages_B = asList(createErrorPageWithServiceId("E_B_1", context_B, ID_B),
+                createErrorPageWithServiceId("E_B_2", context_B, ID_B));
+        ContextRuntime contextRuntime_B = new ContextRuntime(null, errorPages_B, null, null);
+
+        Map<Long, Collection<ServiceReference<?>>> listenerRuntimes = setupListeners();
+
+        setupRegistry(asList(contextHelper_0, contextHelper_A, contextHelper_B),
+                asList(contextRuntime_0, contextRuntime_A, contextRuntime_B),
+//                new ServletRegistryRuntime(servlets, resources),
+                listenerRuntimes,
+                null);
+
+        RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeReference).build();
+
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedFilterDTOs.length);
+        assertEquals(0, runtimeDTO.failedListenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedResourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
+        assertServletContextDTOs(runtimeDTO);
+    }
+
+    private void assertServletContextDTOs(RuntimeDTO runtimeDTO)
+    {
+        SortedSet<Long> seenServiceIds = new TreeSet<Long>();
+
+        assertEquals(3, runtimeDTO.servletContextDTOs.length);
+
+        for (ServletContextDTO servletContextDTO : runtimeDTO.servletContextDTOs)
+        {
+            String contextName = servletContextDTO.name;
+            assertTrue(CONTEXT_NAMES.contains(contextName));
+            if (contextName.equals("0"))
+            {
+                assertTrue(contextName,
+                        servletContextDTO.serviceId < 0);
+                assertEquals(contextName,
+                        1, servletContextDTO.servletDTOs.length);
+                assertEquals(contextName,
+                        1, servletContextDTO.filterDTOs.length);
+                assertEquals(contextName,
+                        1, servletContextDTO.resourceDTOs.length);
+                assertEquals(contextName,
+                        1, servletContextDTO.errorPageDTOs.length);
+                assertEquals(contextName,
+                        2, servletContextDTO.listenerDTOs.length);
+            }
+            else
+            {
+                int expectedId = CONTEXT_NAMES.indexOf(contextName) + 1;
+                assertEquals(contextName,
+                        expectedId, servletContextDTO.serviceId);
+
+                int expectedChildren = CONTEXT_NAMES.indexOf(contextName);
+                assertEquals(contextName,
+                        expectedChildren, servletContextDTO.servletDTOs.length);
+                assertEquals(contextName,
+                        expectedChildren, servletContextDTO.filterDTOs.length);
+                assertEquals(contextName,
+                        expectedChildren, servletContextDTO.resourceDTOs.length);
+                assertEquals(contextName,
+                        expectedChildren, servletContextDTO.errorPageDTOs.length);
+                assertEquals(contextName,
+                        expectedChildren, servletContextDTO.listenerDTOs.length);
+            }
+            seenServiceIds.add(servletContextDTO.serviceId);
+
+            assertEquals(contextName,
+                    3, servletContextDTO.attributes.size());
+            assertEquals(contextName,
+                    1, servletContextDTO.attributes.get("intAttr"));
+            assertEquals(contextName,
+                    "one", servletContextDTO.attributes.get("stringAttr"));
+            assertEquals(contextName,
+                    testDTO, servletContextDTO.attributes.get("dtoAttr"));
+
+            assertEquals(contextName,
+                    2, servletContextDTO.initParams.size());
+            assertEquals(contextName,
+                    "init_val_1", servletContextDTO.initParams.get("param_1"));
+            assertEquals(contextName,
+                    "init_val_2", servletContextDTO.initParams.get("param_2"));
+
+            assertEquals(contextName,
+                    "/" + contextName + "/" + contextName, servletContextDTO.contextPath);
+
+            Collection<Long> serviceIds = assertServletDTOs(contextName,
+                    servletContextDTO.serviceId, servletContextDTO.servletDTOs);
+            seenServiceIds.addAll(serviceIds);
+
+            serviceIds = assertFilterDTOs(contextName,
+                    servletContextDTO.serviceId, servletContextDTO.filterDTOs);
+            seenServiceIds.addAll(serviceIds);
+
+            serviceIds = assertResourceDTOs(contextName,
+                    servletContextDTO.serviceId, servletContextDTO.resourceDTOs);
+            seenServiceIds.addAll(serviceIds);
+
+            serviceIds = assertErrorPageDTOs(contextName,
+                    servletContextDTO.serviceId, servletContextDTO.errorPageDTOs);
+            seenServiceIds.addAll(serviceIds);
+
+            serviceIds = assertListenerDTOs(contextName,
+                    servletContextDTO.serviceId, servletContextDTO.listenerDTOs);
+            seenServiceIds.addAll(serviceIds);
+        }
+        assertEquals(12, seenServiceIds.tailSet(0L).size());
+        assertEquals(9, seenServiceIds.headSet(0L).size());
+    }
+
+    private Collection<Long> assertServletDTOs(String contextName, long contextId, ServletDTO[] dtos) {
+        List<Long> serviceIds = new ArrayList<Long>();
+        for (ServletDTO servletDTO : dtos)
+        {
+            String name = servletDTO.name;
+            assertTrue(CONTEXT_ENTITY_NAMES.get(contextName).contains(name));
+
+            if (contextId != ID_B)
+            {
+                assertTrue(name,
+                        servletDTO.serviceId < 0);
+            }
+            else
+            {
+                assertTrue(name,
+                        servletDTO.serviceId > 0);
+            }
+            serviceIds.add(servletDTO.serviceId);
+
+            assertEquals(name,
+                    contextId, servletDTO.servletContextId);
+
+            assertTrue(name,
+                    servletDTO.asyncSupported);
+
+            assertEquals(name,
+                    2, servletDTO.initParams.size());
+            assertEquals(name,
+                    "valOne_" + name, servletDTO.initParams.get("paramOne_" + name));
+            assertEquals(name,
+                    "valTwo_" + name, servletDTO.initParams.get("paramTwo_" + name));
+
+            assertEquals(name,
+                    1, servletDTO.patterns.length);
+            assertEquals(name,
+                    "/" + name, servletDTO.patterns[0]);
+
+            assertEquals(name,
+                    "info_" + name, servletDTO.servletInfo);
+        }
+
+        return serviceIds;
+    }
+
+    private Collection<Long> assertFilterDTOs(String contextName, long contextId, FilterDTO[] dtos) {
+        List<Long> serviceIds = new ArrayList<Long>();
+        for (FilterDTO filterDTO : dtos)
+        {
+            String name = filterDTO.name;
+            assertTrue(CONTEXT_ENTITY_NAMES.get(contextName).contains(name));
+
+            if (contextId != ID_B)
+            {
+                assertTrue(name,
+                        filterDTO.serviceId < 0);
+            }
+            else
+            {
+                assertTrue(name,
+                        filterDTO.serviceId > 0);
+            }
+            serviceIds.add(filterDTO.serviceId);
+
+            assertEquals(name,
+                    contextId, filterDTO.servletContextId);
+
+            assertTrue(name,
+                    filterDTO.asyncSupported);
+
+            assertEquals(name,
+                    2, filterDTO.initParams.size());
+            assertEquals(name,
+                    "valOne_" + name, filterDTO.initParams.get("paramOne_" + name));
+            assertEquals(name,
+                    "valTwo_" + name, filterDTO.initParams.get("paramTwo_" + name));
+
+            assertEquals(name,
+                    1, filterDTO.patterns.length);
+            assertEquals(name,
+                    "/" + name, filterDTO.patterns[0]);
+
+            assertEquals(name,
+                    1, filterDTO.regexs.length);
+            assertEquals(name,
+                    "." + name, filterDTO.regexs[0]);
+
+            assertEquals(name,
+                    2, filterDTO.dispatcher.length);
+            assertEquals(name,
+                    "ASYNC", filterDTO.dispatcher[0]);
+            assertEquals(name,
+                    "REQUEST", filterDTO.dispatcher[1]);
+        }
+
+        return serviceIds;
+    }
+
+    private Collection<Long> assertResourceDTOs(String contextName, long contextId, ResourceDTO[] dtos) {
+        List<Long> serviceIds = new ArrayList<Long>();
+        for (ResourceDTO resourceDTO : dtos)
+        {
+            if (contextId != ID_B)
+            {
+                assertTrue(contextId + " " + contextName,
+                        resourceDTO.serviceId < 0);
+            }
+            else
+            {
+                assertTrue(contextId + " " + contextName,
+                        resourceDTO.serviceId > 0);
+            }
+            serviceIds.add(resourceDTO.serviceId);
+
+            assertEquals(contextId + " " + contextName,
+                    contextId, resourceDTO.servletContextId);
+
+            assertEquals(contextId + " " + contextName,
+                    1, resourceDTO.patterns.length);
+            assertTrue(contextId + " " + contextName,
+                    resourceDTO.patterns[0].startsWith("/"));
+        }
+        return serviceIds;
+    }
+
+    private Collection<Long> assertErrorPageDTOs(String contextName, long contextId, ErrorPageDTO[] dtos)
+    {
+        List<Long> serviceIds = new ArrayList<Long>();
+        for (ErrorPageDTO  errorPageDTO : dtos)
+        {
+            String name = errorPageDTO.name;
+            assertTrue(CONTEXT_ENTITY_NAMES.get(contextName).contains(name.substring(2)));
+
+            if (contextId != ID_B)
+            {
+                assertTrue(name,
+                        errorPageDTO.serviceId < 0);
+            }
+            else
+            {
+                assertTrue(name,
+                        errorPageDTO.serviceId > 0);
+            }
+            serviceIds.add(errorPageDTO.serviceId);
+
+            assertEquals(name,
+                    contextId, errorPageDTO.servletContextId);
+
+            assertTrue(name,
+                    errorPageDTO.asyncSupported);
+
+            assertEquals(name,
+                    2, errorPageDTO.initParams.size());
+            assertEquals(name,
+                    "valOne_" + name, errorPageDTO.initParams.get("paramOne_" + name));
+            assertEquals(name,
+                    "valTwo_" + name, errorPageDTO.initParams.get("paramTwo_" + name));
+
+            assertEquals(name,
+                    "info_" + name, errorPageDTO.servletInfo);
+
+            assertEquals(name,
+                    2, errorPageDTO.errorCodes.length);
+            long[] errorCodes = copyOf(errorPageDTO.errorCodes, 2);
+            sort(errorCodes);
+            assertEquals(name,
+                    400, errorCodes[0]);
+            assertEquals(name,
+                    500, errorCodes[1]);
+
+            assertEquals(name,
+                    2, errorPageDTO.exceptions.length);
+            String[] exceptions = copyOf(errorPageDTO.exceptions, 2);
+            sort(exceptions);
+            assertEquals(name,
+                    "Bad request", exceptions[0]);
+            assertEquals(name,
+                    "Error", exceptions[1]);
+        }
+
+        return serviceIds;
+    }
+
+    private Collection<Long> assertListenerDTOs(String contextName, long contextId, ListenerDTO[] dtos)
+    {
+        Set<Long> serviceIds = new HashSet<Long>();
+        for (ListenerDTO listenerDTO : dtos)
+        {
+            assertEquals(contextId, listenerDTO.servletContextId);
+            serviceIds.add(listenerDTO.serviceId);
+        }
+
+        assertEquals(ID_LISTENER_1.longValue(), dtos[0].serviceId);
+        assertArrayEquals(new String[] { "org.test.interface_1" },
+                dtos[0].types);
+        if (dtos.length > 1)
+        {
+            assertEquals(ID_LISTENER_2.longValue(), dtos[1].serviceId);
+            assertArrayEquals(new String[] { "org.test.interface_1", "org.test.interface_2" }, dtos[1].types);
+        }
+
+        return serviceIds;
+    }
+
+    @Test
+    public void nullValuesInEntities() {
+        ServletContextHelperRuntime contextHandler = setupContext(context_0, "0", ID_0);
+
+        ServletInfo servletInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "1",
+                new String[] { "/*" },
+                null,
+                true,
+                Collections.<String, String>emptyMap());
+        Servlet servlet = mock(Servlet.class);
+        ServletHandler servletHandler = new HttpServiceServletHandler(0, context_0, servletInfo, servlet);
+        when(servlet.getServletInfo()).thenReturn("info_0");
+
+        FilterInfo filterInfo = createFilterInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "1",
+                null,
+                null,
+                null,
+                true,
+                null,
+                Collections.<String, String>emptyMap());
+        FilterHandler filterHandler = new HttpServiceFilterHandler(0, context_0, filterInfo, mock(Filter.class));
+
+        ServletInfo resourceInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "1",
+                new String[] { "/*" },
+                null,
+                true,
+                Collections.<String, String>emptyMap());
+        Servlet resource = mock(Servlet.class);
+        ServletHandler resourceHandler = new HttpServiceServletHandler(ID_0, context_0, resourceInfo, resource);
+
+        ContextRuntime contextRuntime = new ContextRuntime(null,
+                Collections.<ServletState>emptyList(),
+                null, null);
+        setupRegistry(asList(contextHandler), asList(contextRuntime),
+//                new ServletRegistryRuntime(asList(resourceHandler), asList(servletHandler)),
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                null);
+
+        RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeReference).build();
+
+        assertEquals(1, runtimeDTO.servletContextDTOs.length);
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].filterDTOs.length);
+
+        assertEquals(emptyMap(), runtimeDTO.servletContextDTOs[0].servletDTOs[0].initParams);
+
+        assertEquals(emptyMap(), runtimeDTO.servletContextDTOs[0].filterDTOs[0].initParams);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].filterDTOs[0].patterns.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].filterDTOs[0].regexs.length);
+    }
+
+    @Test
+    public void contextWithNoEntities() {
+        ServletContextHelperRuntime contextHandler_0 = setupContext(context_0, "0", ID_0);
+        ServletContextHelperRuntime contextHandler_A = setupContext(context_A, "A", ID_A);
+
+        // TODO
+        setupRegistry(asList(contextHandler_0, contextHandler_A),
+null, //                asList(ContextRuntime.empty(ID_0), ContextRuntime.empty(ID_A)),
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                null);
+
+        RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeReference).build();
+
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].filterDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[1].servletDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[1].filterDTOs.length);
+    }
+
+    @Test
+    public void missingPatternInServletThrowsException()
+    {
+        expectedException.expect(IllegalArgumentException.class);
+        expectedException.expectMessage("patterns");
+
+        ServletContextHelperRuntime contextHandler = setupContext(context_0, "0", ID_0);
+
+        ServletInfo servletInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "1",
+                null,
+                null,
+                true,
+                Collections.<String, String>emptyMap());
+        Servlet servlet = mock(Servlet.class);
+        ServletHandler servletHandler = new HttpServiceServletHandler(ID_0, context_0, servletInfo, servlet);
+        when(servlet.getServletInfo()).thenReturn("info_0");
+
+        ContextRuntime contextRuntime = new ContextRuntime(Collections.<FilterState>emptyList(),
+                Collections.<ServletState>emptyList(),
+                null, null);
+        setupRegistry(asList(contextHandler), asList(contextRuntime),
+//                new ServletRegistryRuntime(asList(servletHandler), Collections.<ServletRuntime>emptyList()),
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                null);
+
+        new RuntimeDTOBuilder(registry, runtimeReference).build();
+    }
+
+    public FailureRuntime setupFailures()
+    {
+        Map<AbstractInfo<?>, Integer> serviceFailures = new HashMap<AbstractInfo<?>, Integer>();
+
+        ServletContextHelperInfo contextInfo = createContextInfo(0,
+                ID_C,
+                "context_failure_1",
+                "/",
+                createInitParameterMap());
+        serviceFailures.put(contextInfo, 1);
+
+        contextInfo = createContextInfo(0,
+                ID_D,
+                "context_failure_2",
+                "/",
+                createInitParameterMap());
+        serviceFailures.put(contextInfo, 2);
+
+        ServletInfo servletInfo = createServletInfo(0, ID_COUNTER.incrementAndGet(),
+                "servlet_failure_1",
+                new String[] {"/"},
+                null,
+                false,
+                createInitParameterMap());
+        serviceFailures.put(servletInfo, 3);
+
+        servletInfo = createServletInfo(0, ID_COUNTER.incrementAndGet(),
+                "servlet_failure_2",
+                new String[] {"/"},
+                null,
+                false,
+                createInitParameterMap());
+        serviceFailures.put(servletInfo, 4);
+
+        FilterInfo filterInfo = createFilterInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "filter_failure_1",
+                new String[] {"/"},
+                null,
+                null,
+                false,
+                null,
+                createInitParameterMap());
+        serviceFailures.put(filterInfo, 5);
+
+        ServletInfo errorPageInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "error_failure_1",
+                null,
+                new String[] { "405", "TestException" },
+                false,
+                createInitParameterMap());
+        serviceFailures.put(errorPageInfo, 6);
+
+        ServletInfo invalidErrorPageInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "error_failure_2",
+                new String[] { "/" },
+                new String[] { "405", "TestException" },
+                false,
+                createInitParameterMap());
+        serviceFailures.put(invalidErrorPageInfo, 7);
+
+        return FailureRuntime.builder().add(serviceFailures).build();
+    }
+
+    @Test
+    public void testFailureDTOs()
+    {
+        setupRegistry(Collections.<ServletContextHelperRuntime>emptyList(),
+                Collections.<ContextRuntime>emptyList(),
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                setupFailures());
+
+        RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeReference).build();
+
+        assertEquals(0, runtimeDTO.servletContextDTOs.length);
+
+        assertEquals(2, runtimeDTO.failedErrorPageDTOs.length);
+        assertEquals(1, runtimeDTO.failedFilterDTOs.length);
+        // ListenerInfo is hard to setup
+        assertEquals(0, runtimeDTO.failedListenerDTOs.length);
+        // ResourceInfo is hard to setup
+        assertEquals(0, runtimeDTO.failedResourceDTOs.length);
+        assertEquals(2, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(2, runtimeDTO.failedServletDTOs.length);
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs[0].failureReason);
+        assertEquals(2, runtimeDTO.failedServletContextDTOs[1].failureReason);
+        assertEquals(3, runtimeDTO.failedServletDTOs[0].failureReason);
+        assertEquals(4, runtimeDTO.failedServletDTOs[1].failureReason);
+        assertEquals(5, runtimeDTO.failedFilterDTOs[0].failureReason);
+        assertEquals(6, runtimeDTO.failedErrorPageDTOs[0].failureReason);
+        assertEquals(7, runtimeDTO.failedErrorPageDTOs[1].failureReason);
+
+        assertEquals("context_failure_1", runtimeDTO.failedServletContextDTOs[0].name);
+        assertEquals("context_failure_2", runtimeDTO.failedServletContextDTOs[1].name);
+        assertEquals("servlet_failure_1", runtimeDTO.failedServletDTOs[0].name);
+        assertEquals("servlet_failure_2", runtimeDTO.failedServletDTOs[1].name);
+        assertEquals("filter_failure_1", runtimeDTO.failedFilterDTOs[0].name);
+        assertEquals("error_failure_1", runtimeDTO.failedErrorPageDTOs[0].name);
+        assertEquals("error_failure_2", runtimeDTO.failedErrorPageDTOs[1].name);
+
+        assertEquals(ID_C.longValue(), runtimeDTO.failedServletContextDTOs[0].serviceId);
+        assertEquals(ID_D.longValue(), runtimeDTO.failedServletContextDTOs[1].serviceId);
+        assertEquals(0, runtimeDTO.failedServletDTOs[0].servletContextId);
+        assertEquals(0, runtimeDTO.failedServletDTOs[1].servletContextId);
+        assertEquals(0, runtimeDTO.failedFilterDTOs[0].servletContextId);
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs[0].servletContextId);
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs[1].servletContextId);
+
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].errorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].filterDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].listenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].resourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].servletDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].errorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].filterDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].listenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].resourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].servletDTOs.length);
+
+        assertTrue(runtimeDTO.failedServletContextDTOs[0].attributes.isEmpty());
+        assertTrue(runtimeDTO.failedServletContextDTOs[1].attributes.isEmpty());
+    }
+*/
+}
\ No newline at end of file
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/service/HttpServiceFactoryTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/service/HttpServiceFactoryTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/service/HttpServiceFactoryTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/service/HttpServiceFactoryTest.java
diff --git a/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/MimeTypesTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/MimeTypesTest.java
new file mode 100644
index 0000000..df0fcdb
--- /dev/null
+++ b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/MimeTypesTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+public class MimeTypesTest
+{
+    @Test
+    public void testSingleton()
+    {
+        MimeTypes m1 = MimeTypes.get();
+        MimeTypes m2 = MimeTypes.get();
+
+        Assert.assertNotNull(m1);
+        Assert.assertSame(m1, m2);
+
+    }
+
+    @Test
+    public void testGetByFile()
+    {
+        Assert.assertNull(MimeTypes.get().getByFile(null));
+        Assert.assertEquals("text/plain", MimeTypes.get().getByFile("afile.txt"));
+        Assert.assertEquals("text/xml", MimeTypes.get().getByFile(".xml"));
+        Assert.assertNull(MimeTypes.get().getByFile("xml"));
+        Assert.assertNull(MimeTypes.get().getByFile("somefile.notfound"));
+    }
+
+    @Test
+    public void testGetByExtension()
+    {
+        Assert.assertNull(MimeTypes.get().getByExtension(null));
+        Assert.assertEquals("text/plain", MimeTypes.get().getByExtension("txt"));
+        Assert.assertEquals("text/xml", MimeTypes.get().getByExtension("xml"));
+        Assert.assertNull(MimeTypes.get().getByExtension("notfound"));
+    }
+}
diff --git a/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
new file mode 100644
index 0000000..9b8b12c
--- /dev/null
+++ b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Test cases for {@link PatternUtil}.
+ */
+public class PatternUtilTest
+{
+
+    @Test
+    public void testSymbolicName()
+    {
+        assertTrue(PatternUtil.isValidSymbolicName("default"));
+        assertFalse(PatternUtil.isValidSymbolicName("$bad#"));
+        assertTrue(PatternUtil.isValidSymbolicName("abcdefghijklmnopqrstuvwyz"));
+        assertTrue(PatternUtil.isValidSymbolicName("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+        assertTrue(PatternUtil.isValidSymbolicName("0123456789-_"));
+    }
+
+    @Test public void testServletPattern()
+    {
+        assertFalse(PatternUtil.isValidPattern(null));
+        assertTrue(PatternUtil.isValidPattern(""));
+        assertTrue(PatternUtil.isValidPattern("*.html"));
+        assertTrue(PatternUtil.isValidPattern("/"));
+        assertTrue(PatternUtil.isValidPattern("/test"));
+        assertTrue(PatternUtil.isValidPattern("/test/*"));
+        assertTrue(PatternUtil.isValidPattern("/foo/bar"));
+        assertTrue(PatternUtil.isValidPattern("/foo/bar/*"));
+        assertFalse(PatternUtil.isValidPattern("/*.html"));
+        assertFalse(PatternUtil.isValidPattern("/*/foo"));
+        assertFalse(PatternUtil.isValidPattern("foo"));
+        assertFalse(PatternUtil.isValidPattern("foo/bla"));
+        assertFalse(PatternUtil.isValidPattern("/test/"));
+    }
+}
diff --git a/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java
new file mode 100644
index 0000000..41dcca2
--- /dev/null
+++ b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.util;
+
+import static org.apache.felix.http.base.internal.util.UriUtils.concat;
+import static org.apache.felix.http.base.internal.util.UriUtils.decodePath;
+import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Test cases for {@link UriUtils}.
+ */
+public class UriUtilsTest
+{
+    @Test
+    public void testConcatOk()
+    {
+        assertEquals(null, concat(null, null));
+        assertEquals("", concat(null, ""));
+        assertEquals("/", concat(null, "/"));
+        assertEquals("foo", concat(null, "foo"));
+        assertEquals("/foo", concat(null, "/foo"));
+
+        assertEquals("", concat("", null));
+        assertEquals("/", concat("/", null));
+        assertEquals("foo", concat("foo", null));
+        assertEquals("/foo", concat("/foo", null));
+
+        assertEquals("", concat("", ""));
+        assertEquals("foo", concat("", "foo"));
+        assertEquals("/", concat("", "/"));
+        assertEquals("/foo", concat("", "/foo"));
+
+        assertEquals("foo", concat("foo", ""));
+        assertEquals("/", concat("/", ""));
+        assertEquals("/foo", concat("/foo", ""));
+
+        assertEquals("foo", concat("foo", ""));
+        assertEquals("foo/bar", concat("foo", "bar"));
+        assertEquals("foo/", concat("foo", "/"));
+        assertEquals("foo/bar", concat("foo", "/bar"));
+
+        assertEquals("/foo", concat("/", "foo"));
+        assertEquals("/", concat("/", "/"));
+        assertEquals("/bar", concat("/", "/bar"));
+
+        assertEquals("foo/", concat("foo/", null));
+        assertEquals("foo/", concat("foo/", ""));
+        assertEquals("foo/bar", concat("foo/", "bar"));
+        assertEquals("foo/", concat("foo/", "/"));
+        assertEquals("foo/bar", concat("foo/", "/bar"));
+
+        assertEquals("?quu=1", concat("?quu=1", null));
+        assertEquals("?quu=1", concat("?quu=1", ""));
+        assertEquals("foo?quu=1", concat("?quu=1", "foo"));
+        assertEquals("/?quu=1", concat("?quu=1", "/"));
+        assertEquals("/foo?quu=1", concat("?quu=1", "/foo"));
+
+        assertEquals("foo?quu=1", concat("foo?quu=1", null));
+        assertEquals("foo?quu=1", concat("foo?quu=1", ""));
+        assertEquals("foo/bar?quu=1", concat("foo?quu=1", "bar"));
+        assertEquals("foo/?quu=1", concat("foo?quu=1", "/"));
+        assertEquals("foo/bar?quu=1", concat("foo?quu=1", "/bar"));
+
+        assertEquals("foo/?quu=1", concat("foo/?quu=1", null));
+        assertEquals("foo/?quu=1", concat("foo/?quu=1", ""));
+        assertEquals("foo/bar?quu=1", concat("foo/?quu=1", "bar"));
+        assertEquals("foo/?quu=1", concat("foo/?quu=1", "/"));
+        assertEquals("foo/bar?quu=1", concat("foo/?quu=1", "/bar"));
+    }
+
+    @Test
+    public void testDecodePathOk()
+    {
+        assertEquals(null, decodePath(null));
+        assertEquals("foo bar", decodePath("foo%20bar"));
+        assertEquals("foo%23;,:=b a r", decodePath("foo%2523%3b%2c:%3db%20a%20r"));
+        assertEquals("f\u00e4\u00e4%23;,:=b a r=", decodePath("f\u00e4\u00e4%2523%3b%2c:%3db%20a%20r%3D"));
+        assertEquals("f\u0629\u0629%23;,:=b a r", decodePath("f%d8%a9%d8%a9%2523%3b%2c:%3db%20a%20r"));
+    }
+
+    @Test
+    public void testRemoveDotSegmentsOk()
+    {
+        assertEquals(null, removeDotSegments(null));
+        assertEquals("", removeDotSegments(""));
+        assertEquals("", removeDotSegments("."));
+        assertEquals("", removeDotSegments(".."));
+        assertEquals("/", removeDotSegments("/"));
+        assertEquals("/", removeDotSegments("/."));
+        assertEquals("", removeDotSegments("/.."));
+        assertEquals("foo", removeDotSegments("./foo"));
+        assertEquals("/bar/", removeDotSegments("./foo/../bar/"));
+        assertEquals("foo", removeDotSegments("../foo"));
+        assertEquals("/", removeDotSegments("/foo/.."));
+        assertEquals("/foo/", removeDotSegments("/foo/."));
+        assertEquals("/foo/bar", removeDotSegments("/foo/./bar"));
+        assertEquals("/bar", removeDotSegments("/foo/../bar"));
+        assertEquals("/bar", removeDotSegments("/foo/./../bar"));
+        assertEquals("/foo/bar", removeDotSegments("/foo/././bar"));
+        assertEquals("/qux", removeDotSegments("/foo/bar/../../qux"));
+        assertEquals("/foo/qux/quu", removeDotSegments("/foo/bar/../qux/././quu"));
+        assertEquals("/bar//", removeDotSegments("/foo/./../bar//"));
+        assertEquals("/", removeDotSegments("/foo/../bar/.."));
+        assertEquals("/foo/quu", removeDotSegments("/foo/bar/qux/./../../quu"));
+        assertEquals("mid/6", removeDotSegments("mid/content=5/../6"));
+        assertEquals("//bar/qux/file.ext", removeDotSegments("foo/.././/bar/qux/file.ext"));
+        // weird cases
+        assertEquals("..foo", removeDotSegments("..foo"));
+        assertEquals("foo..", removeDotSegments("foo.."));
+        assertEquals("foo.", removeDotSegments("foo."));
+        assertEquals("/.foo", removeDotSegments("/.foo"));
+        assertEquals("/..foo", removeDotSegments("/..foo"));
+
+        // FELIX-4440
+        assertEquals("foo.bar", removeDotSegments("foo.bar"));
+        assertEquals("/test.jsp", removeDotSegments("/test.jsp"));
+        assertEquals("http://foo/bar./qux.quu", removeDotSegments("http://foo/bar./qux.quu"));
+        assertEquals("http://foo/bar.qux/quu", removeDotSegments("http://foo/bar.qux/quu"));
+    }
+}
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java b/http/base-4.x/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
similarity index 100%
copy from http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
copy to http/base-4.x/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base-4.x/src/test/resources/org/apache/felix/http/base/internal/context/resource.txt
similarity index 65%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base-4.x/src/test/resources/org/apache/felix/http/base/internal/context/resource.txt
index 3b210cd..bba492d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base-4.x/src/test/resources/org/apache/felix/http/base/internal/context/resource.txt
@@ -14,26 +14,4 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.registry;
-
-import javax.servlet.http.MappingMatch;
-
-/**
- * Resolution of a servlet based on the path
- */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
-
-    public String[] patterns;
-
-    public String matchedPattern;
-
-    public MappingMatch match;
-
-    public String matchValue;
-}
+Dummy resource...
diff --git a/http/base/README b/http/base/README
new file mode 100644
index 0000000..8976376
--- /dev/null
+++ b/http/base/README
@@ -0,0 +1,5 @@
+This directory contains a proof of concept for a new version of the Apache Felix Http Service.
+
+It is based on Servlet API 5.
+
+This module contains code below the package org.osgi.service.servlet.whiteboard. The API in these packages is NOT official OSGi API, it is work in progress for a new OSGi specifications being worked in the [Eclipse OSGi working group](https://www.osgi.org/). The source is copied from the [design 381 branch](https://github.com/osgi/osgi/tree/design/381). This API might change in any way at any time.
diff --git a/http/base/pom.xml b/http/base/pom.xml
index b6a4135..486ceaf 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>4.2.1-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>
@@ -39,7 +39,7 @@
   </scm>
 
     <properties>
-        <felix.java.version>8</felix.java.version>
+        <felix.java.version>11</felix.java.version>
     </properties>
 
     <dependencies>
@@ -49,8 +49,15 @@
             <version>4.0.1</version>
         </dependency>
         <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>5.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>osgi.core</artifactId>
+            <version>8.0.0</version>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java
index 044ed15..1525251 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/EventDispatcher.java
@@ -18,9 +18,9 @@
  */
 package org.apache.felix.http.base.internal;
 
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionIdListener;
-import javax.servlet.http.HttpSessionListener;
+import jakarta.servlet.http.HttpSessionEvent;
+import jakarta.servlet.http.HttpSessionIdListener;
+import jakarta.servlet.http.HttpSessionListener;
 
 /**
  * The <code>EventDispatcher</code> dispatches events sent from the servlet
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
index 67610f9..570e9fe 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
@@ -18,12 +18,6 @@ package org.apache.felix.http.base.internal;
 
 import java.util.Hashtable;
 
-import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionIdListener;
-import javax.servlet.http.HttpSessionListener;
-
 import org.apache.felix.http.base.internal.dispatch.Dispatcher;
 import org.apache.felix.http.base.internal.dispatch.DispatcherServlet;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
@@ -33,6 +27,15 @@ import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.framework.BundleContext;
 
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSessionEvent;
+import jakarta.servlet.http.HttpSessionIdListener;
+import jakarta.servlet.http.HttpSessionListener;
+
+/**
+ * Controller for the http service
+ */
 public final class HttpServiceController
 {
     private final BundleContext bundleContext;
@@ -46,6 +49,10 @@ public final class HttpServiceController
 
     private volatile HttpSessionListener httpSessionListener;
 
+    /**
+     * Create new controller
+     * @param bundleContext The bundle context
+     */
     public HttpServiceController(final BundleContext bundleContext)
     {
         this.bundleContext = bundleContext;
@@ -56,6 +63,9 @@ public final class HttpServiceController
         this.whiteboardManager = new WhiteboardManager(bundleContext, this.httpServiceFactory, this.registry);
     }
 
+    /**
+     * Stop the controller
+     */
     public void stop()
     {
         this.unregister();
@@ -70,12 +80,16 @@ public final class HttpServiceController
         return new DispatcherServlet(this.dispatcher);
     }
 
-    public EventDispatcher getEventDispatcher()
+    /**
+     * Get the event dispatcher
+     * @return The event dispatcher
+     */
+    public @NotNull EventDispatcher getEventDispatcher()
     {
         return this.eventDispatcher;
     }
 
-    HttpSessionListener getSessionListener()
+    @NotNull HttpSessionListener getSessionListener()
     {
         // we don't need to sync here, if the object gets created several times
         // its not a problem
@@ -97,7 +111,7 @@ public final class HttpServiceController
         return httpSessionListener;
     }
 
-    HttpSessionIdListener getSessionIdListener()
+    @NotNull HttpSessionIdListener getSessionIdListener()
     {
         return new HttpSessionIdListener() {
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java b/http/base/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java
index d48e6f5..992dce2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/console/HttpServicePlugin.java
@@ -31,11 +31,11 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -43,22 +43,22 @@ import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.dto.ServiceReferenceDTO;
-import org.osgi.service.http.runtime.HttpServiceRuntime;
-import org.osgi.service.http.runtime.dto.DTOConstants;
-import org.osgi.service.http.runtime.dto.ErrorPageDTO;
-import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
-import org.osgi.service.http.runtime.dto.FailedFilterDTO;
-import org.osgi.service.http.runtime.dto.FailedListenerDTO;
-import org.osgi.service.http.runtime.dto.FailedResourceDTO;
-import org.osgi.service.http.runtime.dto.FailedServletContextDTO;
-import org.osgi.service.http.runtime.dto.FailedServletDTO;
-import org.osgi.service.http.runtime.dto.FilterDTO;
-import org.osgi.service.http.runtime.dto.ListenerDTO;
-import org.osgi.service.http.runtime.dto.RequestInfoDTO;
-import org.osgi.service.http.runtime.dto.ResourceDTO;
-import org.osgi.service.http.runtime.dto.RuntimeDTO;
-import org.osgi.service.http.runtime.dto.ServletContextDTO;
-import org.osgi.service.http.runtime.dto.ServletDTO;
+import org.osgi.service.servlet.whiteboard.runtime.HttpServiceRuntime;
+import org.osgi.service.servlet.whiteboard.runtime.dto.DTOConstants;
+import org.osgi.service.servlet.whiteboard.runtime.dto.ErrorPageDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FailedErrorPageDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FailedFilterDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FailedListenerDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FailedResourceDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FailedServletContextDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FailedServletDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.FilterDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.ListenerDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.RequestInfoDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.ResourceDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.RuntimeDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.ServletContextDTO;
+import org.osgi.service.servlet.whiteboard.runtime.dto.ServletDTO;
 
 /**
  * This is a web console plugin.
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
index 1dd59fa..a9a6c1e 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContext.java
@@ -18,16 +18,19 @@ package org.apache.felix.http.base.internal.context;
 
 import java.io.IOException;
 
-import javax.servlet.ServletContext;
-import javax.servlet.ServletRequestAttributeListener;
-import javax.servlet.ServletRequestListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSessionAttributeListener;
-import javax.servlet.http.HttpSessionListener;
-
 import org.apache.felix.http.base.internal.HttpConfig;
 
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletRequestAttributeListener;
+import jakarta.servlet.ServletRequestListener;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSessionAttributeListener;
+import jakarta.servlet.http.HttpSessionListener;
+
+/**
+ * Internal extension of the servlet context
+ */
 public interface ExtServletContext extends ServletContext
 {
     boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java
index 6a04c24..25da936 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/context/ExtServletContextWrapper.java
@@ -25,23 +25,23 @@ import java.util.EventListener;
 import java.util.Map;
 import java.util.Set;
 
-import javax.servlet.Filter;
-import javax.servlet.FilterRegistration;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-import javax.servlet.ServletRegistration.Dynamic;
-import javax.servlet.ServletRequestAttributeListener;
-import javax.servlet.ServletRequestListener;
-import javax.servlet.SessionCookieConfig;
-import javax.servlet.SessionTrackingMode;
-import javax.servlet.descriptor.JspConfigDescriptor;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSessionAttributeListener;
-import javax.servlet.http.HttpSessionListener;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterRegistration;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRegistration;
+import jakarta.servlet.ServletRegistration.Dynamic;
+import jakarta.servlet.ServletRequestAttributeListener;
+import jakarta.servlet.ServletRequestListener;
+import jakarta.servlet.SessionCookieConfig;
+import jakarta.servlet.SessionTrackingMode;
+import jakarta.servlet.descriptor.JspConfigDescriptor;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSessionAttributeListener;
+import jakarta.servlet.http.HttpSessionListener;
 
 /**
  * Wrapper of an {code ExtServletContex}.
@@ -297,21 +297,21 @@ public abstract class ExtServletContextWrapper implements ExtServletContext
 	}
 
 	@Override
-    public javax.servlet.FilterRegistration.Dynamic addFilter(
+    public jakarta.servlet.FilterRegistration.Dynamic addFilter(
 	        final String filterName, final String className)
 	{
 		return delegate.addFilter(filterName, className);
 	}
 
 	@Override
-    public javax.servlet.FilterRegistration.Dynamic addFilter(
+    public jakarta.servlet.FilterRegistration.Dynamic addFilter(
 	        final String filterName, final Filter filter)
 	{
 		return delegate.addFilter(filterName, filter);
 	}
 
 	@Override
-    public javax.servlet.FilterRegistration.Dynamic addFilter(
+    public jakarta.servlet.FilterRegistration.Dynamic addFilter(
 	        final String filterName, final Class<? extends Filter> filterClass)
 	{
 		return delegate.addFilter(filterName, filterClass);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
index bcf5d76..cdbb027e 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
@@ -19,27 +19,28 @@ package org.apache.felix.http.base.internal.dispatch;
 import java.io.IOException;
 import java.util.Set;
 
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestEvent;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
+import org.apache.felix.http.base.internal.jakartawrappers.ServletExceptionWrapper;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.registry.HandlerRegistry;
 import org.apache.felix.http.base.internal.registry.PathResolution;
 import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.jetbrains.annotations.Nullable;
-import org.osgi.service.http.whiteboard.Preprocessor;
+import org.osgi.service.servlet.whiteboard.Preprocessor;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletRequestEvent;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
 
 public final class Dispatcher
 {
@@ -152,8 +153,11 @@ public final class Dispatcher
 		            filterChain.doFilter(wrappedRequest, wrappedResponse);
 
 		        }
-		        catch ( final Exception e)
+		        catch ( Exception e)
 		        {
+                    if ( e instanceof ServletExceptionWrapper ) {
+                        e = ((ServletExceptionWrapper)e).getException();
+                    }
 		            SystemLogger.error("Exception while processing request to " + requestURI, e);
 		            req.setAttribute(RequestDispatcher.ERROR_EXCEPTION, e);
 		            req.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, e.getClass().getName());
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java
index 47544bf..ccb3e75 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/DispatcherServlet.java
@@ -18,10 +18,10 @@ package org.apache.felix.http.base.internal.dispatch;
 
 import java.io.IOException;
 
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.apache.felix.http.base.internal.HttpServiceController;
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
index ca547d4..78af52d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
@@ -16,18 +16,18 @@
  */
 package org.apache.felix.http.base.internal.dispatch;
 
-import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
-import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static jakarta.servlet.http.HttpServletResponse.SC_OK;
 
 import java.io.IOException;
 
 import org.jetbrains.annotations.NotNull;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
index ea9813c..fe70c4f 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
@@ -18,13 +18,13 @@ package org.apache.felix.http.base.internal.dispatch;
 
 import java.io.IOException;
 
-import javax.servlet.DispatcherType;
-import javax.servlet.FilterChain;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
 
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.registry.ServletResolution;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
index ce52453..9a01930 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
@@ -16,8 +16,8 @@
  */
 package org.apache.felix.http.base.internal.dispatch;
 
-import javax.servlet.http.HttpServletMapping;
-import javax.servlet.http.MappingMatch;
+import jakarta.servlet.http.HttpServletMapping;
+import jakarta.servlet.http.MappingMatch;
 
 /**
  * Information about the request
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
index 0c676c5..493ce08 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
@@ -16,18 +16,18 @@
  */
 package org.apache.felix.http.base.internal.dispatch;
 
-import static javax.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH;
-import static javax.servlet.RequestDispatcher.FORWARD_MAPPING;
-import static javax.servlet.RequestDispatcher.FORWARD_PATH_INFO;
-import static javax.servlet.RequestDispatcher.FORWARD_QUERY_STRING;
-import static javax.servlet.RequestDispatcher.FORWARD_REQUEST_URI;
-import static javax.servlet.RequestDispatcher.FORWARD_SERVLET_PATH;
-import static javax.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH;
-import static javax.servlet.RequestDispatcher.INCLUDE_MAPPING;
-import static javax.servlet.RequestDispatcher.INCLUDE_PATH_INFO;
-import static javax.servlet.RequestDispatcher.INCLUDE_QUERY_STRING;
-import static javax.servlet.RequestDispatcher.INCLUDE_REQUEST_URI;
-import static javax.servlet.RequestDispatcher.INCLUDE_SERVLET_PATH;
+import static jakarta.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH;
+import static jakarta.servlet.RequestDispatcher.FORWARD_MAPPING;
+import static jakarta.servlet.RequestDispatcher.FORWARD_PATH_INFO;
+import static jakarta.servlet.RequestDispatcher.FORWARD_QUERY_STRING;
+import static jakarta.servlet.RequestDispatcher.FORWARD_REQUEST_URI;
+import static jakarta.servlet.RequestDispatcher.FORWARD_SERVLET_PATH;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_MAPPING;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_PATH_INFO;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_QUERY_STRING;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_REQUEST_URI;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_SERVLET_PATH;
 import static org.apache.felix.http.base.internal.util.UriUtils.concat;
 
 import java.io.File;
@@ -42,31 +42,32 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.servlet.AsyncContext;
-import javax.servlet.DispatcherType;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestAttributeEvent;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletMapping;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpSession;
-import javax.servlet.http.Part;
-
 import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileUpload;
+import org.apache.commons.fileupload.FileUploadBase;
 import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.RequestContext;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
-import org.apache.commons.fileupload.servlet.ServletRequestContext;
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
 import org.osgi.framework.Bundle;
 import org.osgi.service.http.HttpContext;
 import org.osgi.service.useradmin.Authorization;
 
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletRequestAttributeEvent;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletMapping;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.Part;
+
 final class ServletRequestWrapper extends HttpServletRequestWrapper
 {
     private static final List<String> FORBIDDEN_ATTRIBUTES = Arrays.asList(FORWARD_CONTEXT_PATH,
@@ -74,6 +75,11 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
             INCLUDE_CONTEXT_PATH, INCLUDE_MAPPING, INCLUDE_PATH_INFO, INCLUDE_QUERY_STRING, INCLUDE_REQUEST_URI,
             INCLUDE_SERVLET_PATH);
 
+    /**
+     * Constant for HTTP POST method.
+     */
+    private static final String POST_METHOD = "POST";
+
     private final DispatcherType type;
     private final RequestInfo requestInfo;
     private final ExtServletContext servletContext;
@@ -107,7 +113,7 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
         HttpServletRequest request = (HttpServletRequest) getRequest();
         if (isInclusionDispatcher() && !this.requestInfo.nameMatch)
         {
-            // The javax.servlet.include.* attributes refer to the information of the *included* request,
+            // The jakarta.servlet.include.* attributes refer to the information of the *included* request,
             // meaning that the request information comes from the *original* request...
             if (INCLUDE_REQUEST_URI.equals(name))
             {
@@ -136,7 +142,7 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
         }
         else if (isForwardingDispatcher() && !this.requestInfo.nameMatch)
         {
-            // The javax.servlet.forward.* attributes refer to the information of the *original* request,
+            // The jakarta.servlet.forward.* attributes refer to the information of the *original* request,
             // meaning that the request information comes from the *forwarded* request...
             if (FORWARD_REQUEST_URI.equals(name))
             {
@@ -377,11 +383,39 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
         return this.asyncSupported;
     }
 
+
     private Collection<Part> checkMultipart() throws IOException, ServletException
     {
         if ( parts == null )
         {
-            if ( ServletFileUpload.isMultipartContent(this) )
+            final RequestContext multipartContext;
+            if (!POST_METHOD.equalsIgnoreCase(this.getMethod())) {
+                multipartContext = null;
+            } else {
+                multipartContext = new RequestContext() {
+
+                    @Override
+                    public InputStream getInputStream() throws IOException {
+                        return ServletRequestWrapper.this.getInputStream();
+                    }
+
+                    @Override
+                    public String getContentType() {
+                        return ServletRequestWrapper.this.getContentType();
+                    }
+
+                    @Override
+                    public int getContentLength() {
+                        return ServletRequestWrapper.this.getContentLength();
+                    }
+
+                    @Override
+                    public String getCharacterEncoding() {
+                        return ServletRequestWrapper.this.getCharacterEncoding();
+                    }
+                };
+            }
+            if ( multipartContext != null && FileUploadBase.isMultipartContent(multipartContext) )
             {
                 if ( this.multipartConfig == null)
                 {
@@ -390,7 +424,7 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
 
                 if ( System.getSecurityManager() == null )
                 {
-                    handleMultipart();
+                    handleMultipart(multipartContext);
                 }
                 else
                 {
@@ -403,7 +437,7 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
                         {
                             try
                             {
-                                handleMultipart();
+                                handleMultipart(multipartContext);
                             }
                             catch ( final IOException ioe)
                             {
@@ -427,10 +461,10 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
         return parts;
     }
 
-    private void handleMultipart() throws IOException
+    private void handleMultipart(final RequestContext multipartContext) throws IOException
     {
         // Create a new file upload handler
-        final ServletFileUpload upload = new ServletFileUpload();
+        final FileUpload upload = new FileUpload();
         upload.setSizeMax(this.multipartConfig.multipartMaxRequestSize);
         upload.setFileSizeMax(this.multipartConfig.multipartMaxFileSize);
         upload.setFileItemFactory(new DiskFileItemFactory(this.multipartConfig.multipartThreshold,
@@ -440,7 +474,7 @@ final class ServletRequestWrapper extends HttpServletRequestWrapper
         List<FileItem> items = null;
         try
         {
-            items = upload.parseRequest(new ServletRequestContext(this));
+            items = upload.parseRequest(multipartContext);
         }
         catch (final FileUploadException fue)
         {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
index e0a2615..c0e8dbe 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
@@ -19,13 +19,15 @@ package org.apache.felix.http.base.internal.dispatch;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import javax.servlet.DispatcherType;
-import javax.servlet.FilterChain;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponseWrapper;
 
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java
index 342260f..2fa2cbc 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterConfigImpl.java
@@ -20,8 +20,8 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Map;
 
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletContext;
 
 /**
  * Implementation of the filter configuration.
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
index 09de56f..31dcfef 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
@@ -18,20 +18,18 @@ package org.apache.felix.http.base.internal.handler;
 
 import java.io.IOException;
 
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
-import org.apache.felix.http.base.internal.util.ServiceUtils;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.runtime.dto.DTOConstants;
+import org.osgi.service.servlet.whiteboard.runtime.dto.DTOConstants;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 
 /**
  * The filter handler handles the initialization and destruction of filter
@@ -96,7 +94,7 @@ public class FilterHandler implements Comparable<FilterHandler>
             final Filter local = this.filter;
             if ( local != null )
             {
-                name = local.getClass().getName();
+                name = this.filterInfo.getClassName(local);
             }
         }
         return name;
@@ -114,8 +112,7 @@ public class FilterHandler implements Comparable<FilterHandler>
             return -1;
         }
 
-        final ServiceReference<Filter> serviceReference = getFilterInfo().getServiceReference();
-        this.filter = ServiceUtils.safeGetServiceObjects(this.bundleContext, serviceReference);
+        this.filter = getFilterInfo().getService(this.bundleContext);
 
         if (this.filter == null)
         {
@@ -129,9 +126,9 @@ public class FilterHandler implements Comparable<FilterHandler>
         catch (final Exception e)
         {
             SystemLogger.error(this.getFilterInfo().getServiceReference(),
-                    "Error during calling init() on filter " + this.filter,
+                    "Error during calling init() on filter " + this.filterInfo.getClassName(this.filter),
                     e);
-            ServiceUtils.safeUngetServiceObjects(this.bundleContext, serviceReference, this.getFilter());
+            getFilterInfo().ungetService(this.bundleContext, this.filter);
             return DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
         }
 
@@ -171,12 +168,11 @@ public class FilterHandler implements Comparable<FilterHandler>
                 {
                     // we ignore this
                     SystemLogger.error(this.getFilterInfo().getServiceReference(),
-                            "Error during calling destroy() on filter " + f,
+                            "Error during calling destroy() on filter " + this.getFilterInfo().getClassName(f),
                             ignore);
                 }
 
-                ServiceUtils.safeUngetServiceObjects(this.bundleContext,
-                        getFilterInfo().getServiceReference(), f);
+                getFilterInfo().ungetService(this.bundleContext, f);
 
                 return true;
             }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java
index ec1781c..74967e3 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandler.java
@@ -16,24 +16,38 @@
  */
 package org.apache.felix.http.base.internal.handler;
 
-import javax.servlet.Servlet;
-
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.jakartawrappers.ServletWrapper;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 
+import jakarta.servlet.Servlet;
+
 /**
  * Servlet handler for servlets registered through the http service.
  */
 public final class HttpServiceServletHandler extends ServletHandler
 {
+    /**
+     * New handler
+     * @param context The context
+     * @param servletInfo The servlet info
+     * @param servlet The servlet
+     */
     public HttpServiceServletHandler(final ExtServletContext context,
             final ServletInfo servletInfo,
-            final Servlet servlet)
+            final javax.servlet.Servlet servlet)
     {
-        this(HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID, context, servletInfo, servlet);
+        this(HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID, context, servletInfo, ServletWrapper.getRegisteredServlet(servlet));
     }
 
+    /**
+     * New handler
+     * @param contextServiceId The context id
+     * @param context The context
+     * @param servletInfo The servlet info
+     * @param servlet The servlet
+     */
     public HttpServiceServletHandler(final long contextServiceId,
             final ExtServletContext context,
             final ServletInfo servletInfo,
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
index 1b963d6..9165689 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
@@ -27,12 +27,12 @@ import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpSession;
-import javax.servlet.http.HttpSessionBindingEvent;
-import javax.servlet.http.HttpSessionBindingListener;
-import javax.servlet.http.HttpSessionContext;
-import javax.servlet.http.HttpSessionEvent;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSessionBindingEvent;
+import jakarta.servlet.http.HttpSessionBindingListener;
+import jakarta.servlet.http.HttpSessionContext;
+import jakarta.servlet.http.HttpSessionEvent;
 
 import org.apache.felix.http.base.internal.HttpConfig;
 import org.apache.felix.http.base.internal.context.ExtServletContext;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
index 57e3063..c141f3b 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
@@ -20,10 +20,8 @@ import java.util.EventListener;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.ListenerInfo;
-import org.apache.felix.http.base.internal.util.ServiceUtils;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.runtime.dto.DTOConstants;
+import org.osgi.service.servlet.whiteboard.runtime.dto.DTOConstants;
 
 /**
  * The listener handler handles the initialization and destruction of listener
@@ -90,8 +88,7 @@ public class ListenerHandler implements Comparable<ListenerHandler>
             {
                 this.listener = null;
 
-                ServiceUtils.safeUngetServiceObjects(this.bundleContext,
-                        getListenerInfo().getServiceReference(), l);
+                this.getListenerInfo().ungetService(this.bundleContext, l);
 
                 return true;
             }
@@ -118,8 +115,7 @@ public class ListenerHandler implements Comparable<ListenerHandler>
             return -1;
         }
 
-        final ServiceReference<EventListener> serviceReference = getListenerInfo().getServiceReference();
-        this.listener = ServiceUtils.safeGetServiceObjects(this.bundleContext, serviceReference);
+        this.listener = getListenerInfo().getService(this.bundleContext);
 
         final int reason;
         if (this.listener == null)
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java
index b2efa0a..fb076cf 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PreprocessorHandler.java
@@ -18,20 +18,19 @@ package org.apache.felix.http.base.internal.handler;
 
 import java.io.IOException;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.PreprocessorInfo;
-import org.apache.felix.http.base.internal.util.ServiceUtils;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.runtime.dto.DTOConstants;
-import org.osgi.service.http.whiteboard.Preprocessor;
+import org.osgi.service.servlet.whiteboard.runtime.dto.DTOConstants;
+import org.osgi.service.servlet.whiteboard.Preprocessor;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 
 /**
  * The preprocessor handler handles the initialization and destruction of preprocessor
@@ -75,7 +74,7 @@ public class PreprocessorHandler implements Comparable<PreprocessorHandler>
     public int init()
     {
         final ServiceReference<Preprocessor> serviceReference = this.info.getServiceReference();
-        this.preprocessor = ServiceUtils.safeGetService(this.bundleContext, serviceReference);
+        this.preprocessor = this.getPreprocessorInfo().getService(this.bundleContext);
 
         if (this.preprocessor == null)
         {
@@ -91,11 +90,11 @@ public class PreprocessorHandler implements Comparable<PreprocessorHandler>
         catch (final Exception e)
         {
             SystemLogger.error(this.getPreprocessorInfo().getServiceReference(),
-                    "Error during calling init() on preprocessor " + this.preprocessor,
+                    "Error during calling init() on preprocessor " + this.info.getClassName(this.preprocessor),
                     e);
 
+            this.getPreprocessorInfo().ungetService(this.bundleContext, this.preprocessor);
             this.preprocessor = null;
-            ServiceUtils.safeUngetService(this.bundleContext, serviceReference);
 
             return DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
         }
@@ -118,11 +117,11 @@ public class PreprocessorHandler implements Comparable<PreprocessorHandler>
         {
             // we ignore this
             SystemLogger.error(this.getPreprocessorInfo().getServiceReference(),
-                    "Error during calling destroy() on preprocessor " + this.preprocessor,
+                    "Error during calling destroy() on preprocessor " + this.info.getClassName(this.preprocessor),
                     ignore);
         }
+        this.getPreprocessorInfo().ungetService(this.bundleContext, this.preprocessor);
         this.preprocessor = null;
-        ServiceUtils.safeUngetService(this.bundleContext, this.info.getServiceReference());
 
         return true;
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java
index 4ac55d6..dc283fa 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletConfigImpl.java
@@ -20,8 +20,8 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Map;
 
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletContext;
 
 /**
  * Implementation of the servlet configuration
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
index 9a3f2b3..e75f9fc 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
@@ -19,17 +19,18 @@ package org.apache.felix.http.base.internal.handler;
 import java.io.File;
 import java.io.IOException;
 
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.dispatch.MultipartConfig;
+import org.apache.felix.http.base.internal.jakartawrappers.ServletWrapper;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.framework.Bundle;
-import org.osgi.service.http.runtime.dto.DTOConstants;
+import org.osgi.service.servlet.whiteboard.runtime.dto.DTOConstants;
+
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 
 /**
  * The servlet handler handles the initialization and destruction of
@@ -39,7 +40,7 @@ public abstract class ServletHandler implements Comparable<ServletHandler>
 {
     private static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
 
-    private static final String JAVA_SERVLET_TEMP_DIR_PROP = "javax.servlet.content.tempdir";
+    private static final String JAVA_SERVLET_TEMP_DIR_PROP = "jakarta.servlet.content.tempdir";
 
     private final long contextServiceId;
 
@@ -144,7 +145,11 @@ public abstract class ServletHandler implements Comparable<ServletHandler>
             final Servlet local = this.servlet;
             if ( local != null )
             {
-                name = local.getClass().getName();
+                if (local instanceof ServletWrapper ) {
+                    name = ((ServletWrapper)local).getServlet().getClass().getName();
+                } else {
+                    name = local.getClass().getName();
+                }
             }
         }
         return name;
@@ -174,7 +179,7 @@ public abstract class ServletHandler implements Comparable<ServletHandler>
         catch (final Exception e)
         {
             SystemLogger.error(this.getServletInfo().getServiceReference(),
-                    "Error during calling init() on servlet " + this.servlet,
+                    "Error during calling init() on servlet " + this.servletInfo.getClassName(this.servlet),
                     e);
             return DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
         }
@@ -201,7 +206,7 @@ public abstract class ServletHandler implements Comparable<ServletHandler>
             {
                 // we ignore this
                 SystemLogger.error(this.getServletInfo().getServiceReference(),
-                        "Error during calling destroy() on servlet " + this.servlet,
+                        "Error during calling destroy() on servlet " + this.servletInfo.getClassName(this.servlet),
                         ignore);
             }
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java
index 03b5a1a..3cbf2a3 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardServletHandler.java
@@ -18,15 +18,13 @@ package org.apache.felix.http.base.internal.handler;
 
 import java.io.FilePermission;
 
-import javax.servlet.Servlet;
-
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
-import org.apache.felix.http.base.internal.util.ServiceUtils;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.runtime.dto.DTOConstants;
+import org.osgi.service.servlet.whiteboard.runtime.dto.DTOConstants;
+
+import jakarta.servlet.Servlet;
 
 /**
  * Servlet handler for servlets registered through the http whiteboard.
@@ -105,13 +103,12 @@ public final class WhiteboardServletHandler extends ServletHandler
             return -1;
         }
 
-        final ServiceReference<Servlet> serviceReference = getServletInfo().getServiceReference();
-        this.setServlet(ServiceUtils.safeGetServiceObjects(this.bundleContext, serviceReference));
+        this.setServlet(this.getServletInfo().getService(this.bundleContext));
 
         final int reason = super.init();
         if ( reason != -1 )
         {
-            ServiceUtils.safeUngetServiceObjects(this.bundleContext, serviceReference, this.getServlet());
+            this.getServletInfo().ungetService(this.bundleContext, this.getServlet());
             this.setServlet(null);
         }
         return reason;
@@ -125,8 +122,7 @@ public final class WhiteboardServletHandler extends ServletHandler
         {
             if ( super.destroy() )
             {
-                ServiceUtils.safeUngetServiceObjects(this.bundleContext,
-                        getServletInfo().getServiceReference(), s);
+                this.getServletInfo().ungetService(this.bundleContext, this.getServlet());
 
                 return true;
             }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/AsyncContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/AsyncContextWrapper.java
new file mode 100644
index 0000000..4e6fae0
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/AsyncContextWrapper.java
@@ -0,0 +1,109 @@
+/*
+ * 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.jakartawrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * async context wrapper
+ */
+public class AsyncContextWrapper implements AsyncContext {
+
+    private final javax.servlet.AsyncContext context;
+
+    /**
+     * Create new context
+     * @param c Wrapped context
+     */
+    public AsyncContextWrapper(@NotNull final javax.servlet.AsyncContext c) {
+        this.context = c;
+    }
+
+    @Override
+    public ServletRequest getRequest() {
+        return ServletRequestWrapper.getWrapper(context.getRequest());
+    }
+
+    @Override
+    public ServletResponse getResponse() {
+        return ServletResponseWrapper.getWrapper(context.getResponse());
+    }
+
+    @Override
+    public boolean hasOriginalRequestAndResponse() {
+        return context.hasOriginalRequestAndResponse();
+    }
+
+    @Override
+    public void dispatch() {
+        context.dispatch();
+    }
+
+    @Override
+    public void dispatch(final String path) {
+        context.dispatch(path);
+    }
+
+    @Override
+    public void dispatch(final ServletContext sc, final String path) {
+        context.dispatch(new org.apache.felix.http.base.internal.javaxwrappers.ServletContextWrapper(sc), path);
+    }
+
+    @Override
+    public void complete() {
+        context.complete();
+    }
+
+    @Override
+    public void start(final Runnable run) {
+        context.start(run);
+    }
+
+    @Override
+    public void addListener(final AsyncListener listener) {
+        context.addListener(new org.apache.felix.http.base.internal.javaxwrappers.AsyncListenerWrapper(listener));
+    }
+
+    @Override
+    public void addListener(final AsyncListener listener, final ServletRequest servletRequest, final ServletResponse servletResponse) {
+        context.addListener(new org.apache.felix.http.base.internal.javaxwrappers.AsyncListenerWrapper(listener),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(servletRequest),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(servletResponse));
+    }
+
+    @Override
+    public <T extends AsyncListener> T createListener(final Class<T> clazz) throws ServletException {
+        throw new ServletException();
+    }
+
+    @Override
+    public void setTimeout(final long timeout) {
+        context.setTimeout(timeout);
+    }
+
+    @Override
+    public long getTimeout() {
+        return context.getTimeout();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/AsyncListenerWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/AsyncListenerWrapper.java
new file mode 100644
index 0000000..efa0168
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/AsyncListenerWrapper.java
@@ -0,0 +1,76 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+
+/**
+ * Async listener wrapper
+ */
+public class AsyncListenerWrapper implements AsyncListener {
+
+    private final javax.servlet.AsyncListener listener;
+
+    /**
+     * Create new listener
+     * @param c Wrapped listener
+     */
+    public AsyncListenerWrapper(@NotNull final javax.servlet.AsyncListener c) {
+        this.listener = c;
+    }
+
+    @Override
+    public void onComplete(final AsyncEvent event) throws IOException {
+        this.listener.onComplete(new javax.servlet.AsyncEvent(
+                new org.apache.felix.http.base.internal.javaxwrappers.AsyncContextWrapper(event.getAsyncContext()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+
+    @Override
+    public void onTimeout(final AsyncEvent event) throws IOException {
+        this.listener.onTimeout(new javax.servlet.AsyncEvent(
+                new org.apache.felix.http.base.internal.javaxwrappers.AsyncContextWrapper(event.getAsyncContext()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+
+    @Override
+    public void onError(final AsyncEvent event) throws IOException {
+        this.listener.onError(new javax.servlet.AsyncEvent(
+                new org.apache.felix.http.base.internal.javaxwrappers.AsyncContextWrapper(event.getAsyncContext()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+
+    @Override
+    public void onStartAsync(final AsyncEvent event) throws IOException {
+        this.listener.onStartAsync(new javax.servlet.AsyncEvent(
+                new org.apache.felix.http.base.internal.javaxwrappers.AsyncContextWrapper(event.getAsyncContext()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/CookieWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/CookieWrapper.java
new file mode 100644
index 0000000..d4be990
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/CookieWrapper.java
@@ -0,0 +1,111 @@
+/*
+ * 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.jakartawrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.Cookie;
+
+/**
+ * Cookie
+ */
+public class CookieWrapper extends Cookie {
+
+    private static final long serialVersionUID = 5230437594501050941L;
+
+    /**
+     * Wrap an array of cookies
+     * @param array The array
+     * @return The result
+     */
+    public static Cookie[] wrap(final javax.servlet.http.Cookie[] array) {
+        if ( array == null ) {
+            return null;
+        }
+        final Cookie[] result = new Cookie[array.length];
+        for(int i=0;i<array.length;i++) {
+            result[i] = new CookieWrapper(array[i]);
+        }
+        return result;
+    }
+
+    private final javax.servlet.http.Cookie cookie;
+
+    /**
+     * Create new cookie
+     * @param c Wrapped cookie
+     */
+    public CookieWrapper(@NotNull final javax.servlet.http.Cookie c) {
+        super(c.getName(), c.getValue());
+        this.cookie = c;
+        super.setComment(c.getComment());
+        super.setDomain(c.getDomain());
+        super.setHttpOnly(c.isHttpOnly());
+        super.setMaxAge(c.getMaxAge());
+        super.setPath(c.getPath());
+        super.setSecure(c.getSecure());
+        super.setVersion(c.getVersion());
+    }
+
+    @Override
+    public void setComment(final String purpose) {
+        this.cookie.setComment(purpose);
+        super.setComment(purpose);
+    }
+
+    @Override
+    public void setDomain(final String domain) {
+        this.cookie.setDomain(domain);
+        super.setDomain(domain);
+    }
+
+    @Override
+    public void setMaxAge(final int expiry) {
+        this.cookie.setMaxAge(expiry);
+        super.setMaxAge(expiry);
+    }
+
+    @Override
+    public void setPath(final String uri) {
+        this.cookie.setPath(uri);
+        super.setPath(uri);
+    }
+
+    @Override
+    public void setSecure(final boolean flag) {
+        this.cookie.setSecure(flag);
+        super.setSecure(flag);
+    }
+
+    @Override
+    public void setValue(final String newValue) {
+        this.cookie.setValue(newValue);
+        super.setValue(newValue);
+    }
+
+    @Override
+    public void setVersion(final int v) {
+        this.cookie.setVersion(v);
+        super.setVersion(v);
+    }
+
+    @Override
+    public void setHttpOnly(final boolean isHttpOnly) {
+        this.cookie.setHttpOnly(isHttpOnly);
+        super.setHttpOnly(isHttpOnly);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/EventListenerWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/EventListenerWrapper.java
new file mode 100644
index 0000000..3f540d2
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/EventListenerWrapper.java
@@ -0,0 +1,229 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.EventListener;
+import java.util.Set;
+
+import org.apache.felix.http.base.internal.javaxwrappers.HttpSessionWrapper;
+import org.apache.felix.http.base.internal.javaxwrappers.ServletContextWrapper;
+import org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper;
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletContextAttributeEvent;
+import jakarta.servlet.ServletContextAttributeListener;
+import jakarta.servlet.ServletContextEvent;
+import jakarta.servlet.ServletContextListener;
+import jakarta.servlet.ServletRequestAttributeEvent;
+import jakarta.servlet.ServletRequestAttributeListener;
+import jakarta.servlet.ServletRequestEvent;
+import jakarta.servlet.ServletRequestListener;
+import jakarta.servlet.http.HttpSessionAttributeListener;
+import jakarta.servlet.http.HttpSessionBindingEvent;
+import jakarta.servlet.http.HttpSessionEvent;
+import jakarta.servlet.http.HttpSessionIdListener;
+import jakarta.servlet.http.HttpSessionListener;
+
+/**
+ * Wrapper for all listeners
+ */
+public class EventListenerWrapper implements HttpSessionAttributeListener,
+    HttpSessionIdListener,
+    HttpSessionListener,
+    ServletContextListener,
+    ServletContextAttributeListener,
+    ServletRequestListener,
+    ServletRequestAttributeListener {
+
+    private final javax.servlet.http.HttpSessionAttributeListener httpSessionAttributeListener;
+    private final javax.servlet.http.HttpSessionIdListener httpSessionIdListener;
+    private final javax.servlet.http.HttpSessionListener httpSessionListener;
+    private final javax.servlet.ServletContextListener servletContextListener;
+    private final javax.servlet.ServletContextAttributeListener servletContextAttributeListener;
+    private final javax.servlet.ServletRequestListener servletRequestListener;
+    private final javax.servlet.ServletRequestAttributeListener servletRequestAttributeListener;
+    private final EventListener listener;
+
+    /**
+     * Create new wrapper
+     * @param listener Wrapped listener
+     * @param listenerTypes Service interfaces
+     */
+    public EventListenerWrapper(@NotNull final EventListener listener,
+            @NotNull final Set<String> listenerTypes) {
+        this.listener = listener;
+        if ( listenerTypes.contains(HttpSessionAttributeListener.class.getName()) ) {
+            this.httpSessionAttributeListener = (javax.servlet.http.HttpSessionAttributeListener) listener;
+        } else {
+            this.httpSessionAttributeListener = null;
+        }
+        if ( listenerTypes.contains(HttpSessionIdListener.class.getName()) ) {
+            this.httpSessionIdListener = (javax.servlet.http.HttpSessionIdListener) listener;
+        } else {
+            this.httpSessionIdListener = null;
+        }
+        if ( listenerTypes.contains(HttpSessionListener.class.getName()) ) {
+            this.httpSessionListener = (javax.servlet.http.HttpSessionListener) listener;
+        } else {
+            this.httpSessionListener = null;
+        }
+        if ( listenerTypes.contains(ServletContextListener.class.getName()) ) {
+            this.servletContextListener = (javax.servlet.ServletContextListener) listener;
+        } else {
+            this.servletContextListener = null;
+        }
+        if ( listenerTypes.contains(ServletContextAttributeListener.class.getName()) ) {
+            this.servletContextAttributeListener = (javax.servlet.ServletContextAttributeListener) listener;
+        } else {
+            this.servletContextAttributeListener = null;
+        }
+        if ( listenerTypes.contains(ServletRequestListener.class.getName()) ) {
+            this.servletRequestListener = (javax.servlet.ServletRequestListener) listener;
+        } else {
+            this.servletRequestListener = null;
+        }
+        if ( listenerTypes.contains(ServletRequestAttributeListener.class.getName()) ) {
+            this.servletRequestAttributeListener = (javax.servlet.ServletRequestAttributeListener) listener;
+        } else {
+            this.servletRequestAttributeListener = null;
+        }
+    }
+
+    @Override
+    public void attributeAdded(final ServletRequestAttributeEvent srae) {
+        if ( this.servletRequestAttributeListener != null ) {
+            this.servletRequestAttributeListener.attributeAdded(new javax.servlet.ServletRequestAttributeEvent(new ServletContextWrapper(srae.getServletContext()),
+                    ServletRequestWrapper.getWrapper(srae.getServletRequest()), srae.getName(), srae.getValue()));
+        }
+    }
+    @Override
+    public void attributeRemoved(final ServletRequestAttributeEvent srae) {
+        if ( this.servletRequestAttributeListener != null ) {
+            this.servletRequestAttributeListener.attributeRemoved(new javax.servlet.ServletRequestAttributeEvent(new ServletContextWrapper(srae.getServletContext()),
+                    ServletRequestWrapper.getWrapper(srae.getServletRequest()), srae.getName(), srae.getValue()));
+        }
+    }
+
+    @Override
+    public void attributeReplaced(final ServletRequestAttributeEvent srae) {
+        if ( this.servletRequestAttributeListener != null ) {
+            this.servletRequestAttributeListener.attributeReplaced(new javax.servlet.ServletRequestAttributeEvent(new ServletContextWrapper(srae.getServletContext()),
+                    ServletRequestWrapper.getWrapper(srae.getServletRequest()), srae.getName(), srae.getValue()));
+        }
+    }
+
+    @Override
+    public void requestDestroyed(final ServletRequestEvent sre) {
+        if ( this.servletRequestListener != null ) {
+            this.servletRequestListener.requestDestroyed(new javax.servlet.ServletRequestEvent(new ServletContextWrapper(sre.getServletContext()),
+                    ServletRequestWrapper.getWrapper(sre.getServletRequest())));
+        }
+    }
+
+    @Override
+    public void requestInitialized(final ServletRequestEvent sre) {
+        if ( this.servletRequestListener != null ) {
+            this.servletRequestListener.requestInitialized(new javax.servlet.ServletRequestEvent(new ServletContextWrapper(sre.getServletContext()),
+                    ServletRequestWrapper.getWrapper(sre.getServletRequest())));
+        }
+    }
+
+    @Override
+    public void attributeAdded(final ServletContextAttributeEvent event) {
+        if ( this.servletContextAttributeListener != null ) {
+            this.servletContextAttributeListener.attributeAdded(new javax.servlet.ServletContextAttributeEvent(new ServletContextWrapper(event.getServletContext()), event.getName(), event.getValue()));
+        }
+    }
+
+    @Override
+    public void attributeRemoved(final ServletContextAttributeEvent event) {
+        if ( this.servletContextAttributeListener != null ) {
+            this.servletContextAttributeListener.attributeRemoved(new javax.servlet.ServletContextAttributeEvent(new ServletContextWrapper(event.getServletContext()), event.getName(), event.getValue()));
+        }
+    }
+
+    @Override
+    public void attributeReplaced(final ServletContextAttributeEvent event) {
+        if ( this.servletContextAttributeListener != null ) {
+            this.servletContextAttributeListener.attributeReplaced(new javax.servlet.ServletContextAttributeEvent(new ServletContextWrapper(event.getServletContext()), event.getName(), event.getValue()));
+        }
+    }
+
+    @Override
+    public void contextInitialized(final ServletContextEvent sce) {
+        if ( this.servletContextListener != null ) {
+            this.servletContextListener.contextInitialized(new javax.servlet.ServletContextEvent(new ServletContextWrapper(sce.getServletContext())));
+        }
+    }
+
+    @Override
+    public void contextDestroyed(final ServletContextEvent sce) {
+        if ( this.servletContextListener != null ) {
+            this.servletContextListener.contextDestroyed(new javax.servlet.ServletContextEvent(new ServletContextWrapper(sce.getServletContext())));
+        }
+    }
+
+    @Override
+    public void sessionCreated(final HttpSessionEvent se) {
+        if ( this.httpSessionListener != null ) {
+            this.httpSessionListener.sessionCreated(new javax.servlet.http.HttpSessionEvent(new HttpSessionWrapper(se.getSession())));
+        }
+    }
+
+    @Override
+    public void sessionDestroyed(final HttpSessionEvent se) {
+        if ( this.httpSessionListener != null ) {
+            this.httpSessionListener.sessionDestroyed(new javax.servlet.http.HttpSessionEvent(new HttpSessionWrapper(se.getSession())));
+        }
+    }
+
+    @Override
+    public void sessionIdChanged(final HttpSessionEvent event, final String oldSessionId) {
+        if ( this.httpSessionIdListener != null ) {
+            this.httpSessionIdListener.sessionIdChanged(new javax.servlet.http.HttpSessionEvent(new HttpSessionWrapper(event.getSession())), oldSessionId);
+        }
+    }
+
+    @Override
+    public void attributeAdded(final HttpSessionBindingEvent event) {
+        if ( this.httpSessionAttributeListener != null ) {
+            this.httpSessionAttributeListener.attributeAdded(new javax.servlet.http.HttpSessionBindingEvent(new HttpSessionWrapper(event.getSession()), event.getName(), event.getValue()));
+        }
+    }
+
+    @Override
+    public void attributeRemoved(final HttpSessionBindingEvent event) {
+        if ( this.httpSessionAttributeListener != null ) {
+            this.httpSessionAttributeListener.attributeRemoved(new javax.servlet.http.HttpSessionBindingEvent(new HttpSessionWrapper(event.getSession()), event.getName(), event.getValue()));
+        }
+    }
+
+    @Override
+    public void attributeReplaced(final HttpSessionBindingEvent event) {
+        if ( this.httpSessionAttributeListener != null ) {
+            this.httpSessionAttributeListener.attributeReplaced(new javax.servlet.http.HttpSessionBindingEvent(new HttpSessionWrapper(event.getSession()), event.getName(), event.getValue()));
+        }
+    }
+
+    /**
+     * Get the listener
+     * @return The listener
+     */
+    public @NotNull EventListener getListener() {
+        return this.listener;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/FilterRegistrationWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/FilterRegistrationWrapper.java
new file mode 100644
index 0000000..e8bb143
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/FilterRegistrationWrapper.java
@@ -0,0 +1,115 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.FilterRegistration;
+
+/**
+ * Filter registration wrapper
+ */
+public class FilterRegistrationWrapper implements FilterRegistration {
+
+    private final javax.servlet.FilterRegistration reg;
+
+    /**
+     * Create new wrapper
+     * @param c Wrapped registration
+     */
+    public FilterRegistrationWrapper(@NotNull final javax.servlet.FilterRegistration c) {
+        this.reg = c;
+    }
+
+    private EnumSet<javax.servlet.DispatcherType> wrap(final EnumSet<DispatcherType> dispatcherTypes) {
+        final EnumSet<javax.servlet.DispatcherType> set = EnumSet.noneOf(javax.servlet.DispatcherType.class);
+        if ( dispatcherTypes.contains(DispatcherType.ASYNC)) {
+            set.add(javax.servlet.DispatcherType.ASYNC);
+        }
+        if ( dispatcherTypes.contains(DispatcherType.ERROR)) {
+            set.add(javax.servlet.DispatcherType.ERROR);
+        }
+        if ( dispatcherTypes.contains(DispatcherType.FORWARD)) {
+            set.add(javax.servlet.DispatcherType.FORWARD);
+        }
+        if ( dispatcherTypes.contains(DispatcherType.INCLUDE)) {
+            set.add(javax.servlet.DispatcherType.INCLUDE);
+        }
+        if ( dispatcherTypes.contains(DispatcherType.REQUEST)) {
+            set.add(javax.servlet.DispatcherType.REQUEST);
+        }
+        return set;
+    }
+
+    @Override
+    public void addMappingForServletNames(final EnumSet<DispatcherType> dispatcherTypes, final boolean isMatchAfter,
+            final String... servletNames) {
+        reg.addMappingForServletNames(wrap(dispatcherTypes), isMatchAfter, servletNames);
+    }
+
+    @Override
+    public String getName() {
+        return reg.getName();
+    }
+
+    @Override
+    public String getClassName() {
+        return reg.getClassName();
+    }
+
+    @Override
+    public boolean setInitParameter(final String name, final String value) {
+        return reg.setInitParameter(name, value);
+    }
+
+    @Override
+    public Collection<String> getServletNameMappings() {
+        return reg.getServletNameMappings();
+    }
+
+    @Override
+    public void addMappingForUrlPatterns(final EnumSet<DispatcherType> dispatcherTypes, final boolean isMatchAfter,
+            final String... urlPatterns) {
+        reg.addMappingForUrlPatterns(wrap(dispatcherTypes), isMatchAfter, urlPatterns);
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        return reg.getInitParameter(name);
+    }
+
+    @Override
+    public Set<String> setInitParameters(final Map<String, String> initParameters) {
+        return reg.setInitParameters(initParameters);
+    }
+
+    @Override
+    public Collection<String> getUrlPatternMappings() {
+        return reg.getUrlPatternMappings();
+    }
+
+    @Override
+    public Map<String, String> getInitParameters() {
+        return reg.getInitParameters();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/FilterWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/FilterWrapper.java
new file mode 100644
index 0000000..1e66ca0
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/FilterWrapper.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * Jakarta Filter based on a javax filter
+ */
+public class FilterWrapper implements Filter {
+
+    private final javax.servlet.Filter filter;
+
+    /**
+     * Create new filter
+     * @param filter wrapped filter
+     */
+    public FilterWrapper(@NotNull final javax.servlet.Filter filter) {
+        this.filter = filter;
+    }
+
+    @Override
+    public void init(final FilterConfig filterConfig) throws ServletException {
+        try {
+            this.filter.init(new org.apache.felix.http.base.internal.javaxwrappers.FilterConfigWrapper(filterConfig));
+        } catch (final javax.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
+        try {
+            this.filter.doFilter(org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(request),
+                    org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(response),
+                    new org.apache.felix.http.base.internal.javaxwrappers.FilterChainWrapper(chain));
+        } catch (final javax.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        this.filter.destroy();
+    }
+
+    /**
+     * Get the filter
+     * @return The filter
+     */
+    public @NotNull javax.servlet.Filter getFilter() {
+        return this.filter;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletMappingWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletMappingWrapper.java
new file mode 100644
index 0000000..22a5aea
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletMappingWrapper.java
@@ -0,0 +1,73 @@
+/*
+ * 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.jakartawrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.HttpServletMapping;
+import jakarta.servlet.http.MappingMatch;
+
+/**
+ * Http Mapping wrapper
+ */
+public class HttpServletMappingWrapper implements HttpServletMapping {
+
+    private final javax.servlet.http.HttpServletMapping mapping;
+
+    /**
+     * Create new wrapper
+     * @param c Wrapped mapper
+     */
+    public HttpServletMappingWrapper(@NotNull final javax.servlet.http.HttpServletMapping c) {
+        this.mapping = c;
+    }
+
+    @Override
+    public String getMatchValue() {
+        return mapping.getMatchValue();
+    }
+
+    @Override
+    public String getPattern() {
+        return mapping.getPattern();
+    }
+
+    @Override
+    public String getServletName() {
+        return mapping.getServletName();
+    }
+
+    @Override
+    public MappingMatch getMappingMatch() {
+        switch (mapping.getMappingMatch()) {
+        case CONTEXT_ROOT : return MappingMatch.CONTEXT_ROOT;
+        case DEFAULT : return MappingMatch.DEFAULT;
+        case EXACT : return MappingMatch.EXACT;
+        case EXTENSION : return MappingMatch.EXTENSION;
+        case PATH : return MappingMatch.PATH;
+        }
+        return null;
+    }
+
+    /**
+     * Get the wrapped mapping
+     * @return The mapping
+     */
+    public javax.servlet.http.HttpServletMapping getMapping() {
+        return this.mapping;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletRequestWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletRequestWrapper.java
new file mode 100644
index 0000000..35cc59f
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletRequestWrapper.java
@@ -0,0 +1,268 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletMapping;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpUpgradeHandler;
+import jakarta.servlet.http.Part;
+import jakarta.servlet.http.PushBuilder;
+
+/**
+ * Http servlet request wrapper
+ */
+public class HttpServletRequestWrapper extends ServletRequestWrapper
+    implements HttpServletRequest {
+
+    private final javax.servlet.http.HttpServletRequest request;
+
+    /**
+     * Create new wrapper
+     * @param r Wrapped request
+     */
+    public HttpServletRequestWrapper(@NotNull final javax.servlet.http.HttpServletRequest r) {
+        super(r);
+        this.request = r;
+    }
+
+    @Override
+    public String getAuthType() {
+        return this.request.getAuthType();
+    }
+
+    @Override
+    public Cookie[] getCookies() {
+        return CookieWrapper.wrap(this.request.getCookies());
+    }
+
+    @Override
+    public long getDateHeader(final String name) {
+        return this.request.getDateHeader(name);
+    }
+
+    @Override
+    public String getHeader(final String name) {
+        return this.request.getHeader(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaders(final String name) {
+        return this.request.getHeaders(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaderNames() {
+        return this.request.getHeaderNames();
+    }
+
+    @Override
+    public int getIntHeader(final String name) {
+        return this.request.getIntHeader(name);
+    }
+
+    @Override
+    public String getMethod() {
+        return this.request.getMethod();
+    }
+
+    @Override
+    public String getPathInfo() {
+        return this.request.getPathInfo();
+    }
+
+    @Override
+    public String getPathTranslated() {
+        return this.request.getPathTranslated();
+    }
+
+    @Override
+    public String getContextPath() {
+        return this.request.getContextPath();
+    }
+
+    @Override
+    public String getQueryString() {
+        return this.request.getQueryString();
+    }
+
+    @Override
+    public String getRemoteUser() {
+        return this.request.getRemoteUser();
+    }
+
+    @Override
+    public boolean isUserInRole(final String role) {
+        return this.request.isUserInRole(role);
+    }
+
+    @Override
+    public Principal getUserPrincipal() {
+        return this.request.getUserPrincipal();
+    }
+
+    @Override
+    public String getRequestedSessionId() {
+        return this.request.getRequestedSessionId();
+    }
+
+    @Override
+    public String getRequestURI() {
+        return this.request.getRequestURI();
+    }
+
+    @Override
+    public StringBuffer getRequestURL() {
+        return this.request.getRequestURL();
+    }
+
+    @Override
+    public String getServletPath() {
+        return this.request.getServletPath();
+    }
+
+    @Override
+    public HttpSession getSession(final boolean create) {
+        final javax.servlet.http.HttpSession session = this.request.getSession(create);
+        if ( session != null ) {
+            return new HttpSessionWrapper(session);
+        }
+        return null;
+    }
+
+    @Override
+    public HttpSession getSession() {
+        return new HttpSessionWrapper(this.request.getSession());
+    }
+
+    @Override
+    public String changeSessionId() {
+        return this.request.changeSessionId();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        return this.request.isRequestedSessionIdValid();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromCookie() {
+        return this.request.isRequestedSessionIdFromCookie();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromURL() {
+        return this.request.isRequestedSessionIdFromURL();
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public boolean isRequestedSessionIdFromUrl() {
+        return this.request.isRequestedSessionIdFromUrl();
+    }
+
+    @Override
+    public boolean authenticate(final HttpServletResponse response) throws IOException, ServletException {
+        try {
+            return this.request.authenticate((javax.servlet.http.HttpServletResponse)org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(response));
+        } catch ( final javax.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void login(final String username, final String password) throws ServletException {
+        try {
+            this.request.login(username, password);
+        } catch ( final javax.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void logout() throws ServletException {
+        try {
+            this.request.logout();
+        } catch ( final javax.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public Collection<Part> getParts() throws IOException, ServletException {
+        try {
+            final List<Part> result = new ArrayList<>();
+            for(final javax.servlet.http.Part p : this.request.getParts()) {
+                result.add(new PartWrapper(p));
+            }
+            return result;
+        } catch ( final javax.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public Part getPart(final String name) throws IOException, ServletException {
+        try {
+            return new PartWrapper(this.request.getPart(name));
+        } catch ( final javax.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public <T extends HttpUpgradeHandler> T upgrade(final Class<T> handlerClass) throws IOException, ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public HttpServletMapping getHttpServletMapping() {
+        return new HttpServletMappingWrapper(this.request.getHttpServletMapping());
+    }
+
+    @Override
+    public PushBuilder newPushBuilder() {
+        final javax.servlet.http.PushBuilder builder = this.request.newPushBuilder();
+        if ( builder != null ) {
+            return new PushBuilderWrapper(builder);
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getTrailerFields() {
+        return this.request.getTrailerFields();
+    }
+
+    @Override
+    public boolean isTrailerFieldsReady() {
+        return this.request.isTrailerFieldsReady();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletResponseWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletResponseWrapper.java
new file mode 100644
index 0000000..4cc2cbc
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpServletResponseWrapper.java
@@ -0,0 +1,151 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * Http servlet response wrapper
+*/
+public class HttpServletResponseWrapper extends ServletResponseWrapper
+    implements HttpServletResponse {
+
+    private final javax.servlet.http.HttpServletResponse response;
+
+    /**
+     * Create a new response
+     * @param r Wrapped response
+     */
+    public HttpServletResponseWrapper(@NotNull final javax.servlet.http.HttpServletResponse r) {
+        super(r);
+        this.response = r;
+    }
+
+    @Override
+    public void addCookie(final Cookie cookie) {
+        this.response.addCookie(new org.apache.felix.http.base.internal.javaxwrappers.CookieWrapper(cookie));
+    }
+
+    @Override
+    public boolean containsHeader(final String name) {
+        return this.response.containsHeader(name);
+    }
+
+    @Override
+    public String encodeURL(final String url) {
+        return this.response.encodeURL(url);
+    }
+
+    @Override
+    public String encodeRedirectURL(final String url) {
+        return this.response.encodeRedirectURL(url);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public String encodeUrl(final String url) {
+        return this.response.encodeUrl(url);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public String encodeRedirectUrl(final String url) {
+        return this.response.encodeRedirectUrl(url);
+    }
+
+    @Override
+    public void sendError(final int sc, final String msg) throws IOException {
+        this.response.sendError(sc, msg);
+    }
+
+    @Override
+    public void sendError(final int sc) throws IOException {
+        this.response.sendError(sc);
+    }
+
+    @Override
+    public void sendRedirect(final String location) throws IOException {
+        this.response.sendRedirect(location);
+    }
+
+    @Override
+    public void setDateHeader(final String name, final long date) {
+        this.response.setDateHeader(name, date);
+    }
+
+    @Override
+    public void addDateHeader(final String name, final long date) {
+        this.response.addDateHeader(name, date);
+    }
+
+    @Override
+    public void setHeader(final String name, final String value) {
+        this.response.setHeader(name, value);
+    }
+
+    @Override
+    public void addHeader(final String name, final String value) {
+        this.response.addHeader(name, value);
+    }
+
+    @Override
+    public void setIntHeader(final String name, final int value) {
+        this.response.setIntHeader(name, value);
+    }
+
+    @Override
+    public void addIntHeader(final String name, final int value) {
+        this.response.addIntHeader(name, value);
+    }
+
+    @Override
+    public void setStatus(int sc) {
+        this.response.setStatus(sc);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void setStatus(final int sc, final String sm) {
+        this.response.setStatus(sc, sm);
+    }
+
+    @Override
+    public int getStatus() {
+        return this.response.getStatus();
+    }
+
+    @Override
+    public String getHeader(final String name) {
+        return this.response.getHeader(name);
+    }
+
+    @Override
+    public Collection<String> getHeaders(final String name) {
+        return this.response.getHeaders(name);
+    }
+
+    @Override
+    public Collection<String> getHeaderNames() {
+        return this.response.getHeaderNames();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpSessionContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpSessionContextWrapper.java
new file mode 100644
index 0000000..786a84b
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpSessionContextWrapper.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.Enumeration;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSessionContext;
+
+/**
+ * http session context wrapper
+ */
+@SuppressWarnings("deprecation")
+public class HttpSessionContextWrapper implements HttpSessionContext {
+
+    private final javax.servlet.http.HttpSessionContext context;
+
+    /**
+     * Create new context
+     * @param c Wrapped context
+     */
+    public HttpSessionContextWrapper(@NotNull final javax.servlet.http.HttpSessionContext c) {
+        this.context = c;
+    }
+
+    @Override
+    public HttpSession getSession(final String sessionId) {
+        final javax.servlet.http.HttpSession session = context.getSession(sessionId);
+        if ( session != null ) {
+            return new HttpSessionWrapper(session);
+        }
+        return null;
+    }
+
+    @Override
+    public Enumeration<String> getIds() {
+        return context.getIds();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpSessionWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpSessionWrapper.java
new file mode 100644
index 0000000..27dc9dd
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/HttpSessionWrapper.java
@@ -0,0 +1,132 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.Enumeration;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSessionContext;
+
+/**
+ * Http session wrapper
+ */
+public class HttpSessionWrapper implements HttpSession {
+
+    private final javax.servlet.http.HttpSession session;
+
+    /**
+     * Create new session
+     * @param session Wrapped session
+     */
+    public HttpSessionWrapper(@NotNull final javax.servlet.http.HttpSession session) {
+        this.session = session;
+    }
+
+
+    @Override
+    public long getCreationTime() {
+        return session.getCreationTime();
+    }
+
+    @Override
+    public String getId() {
+        return session.getId();
+    }
+
+    @Override
+    public long getLastAccessedTime() {
+        return session.getLastAccessedTime();
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return new ServletContextWrapper(session.getServletContext());
+    }
+
+    @Override
+    public void setMaxInactiveInterval(int interval) {
+        session.setMaxInactiveInterval(interval);
+    }
+
+    @Override
+    public int getMaxInactiveInterval() {
+        return session.getMaxInactiveInterval();
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public HttpSessionContext getSessionContext() {
+        return new HttpSessionContextWrapper(session.getSessionContext());
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return session.getAttribute(name);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public Object getValue(String name) {
+        return session.getValue(name);
+    }
+
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return session.getAttributeNames();
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public String[] getValueNames() {
+        return session.getValueNames();
+    }
+
+    @Override
+    public void setAttribute(String name, Object value) {
+        session.setAttribute(name, value);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void putValue(String name, Object value) {
+        session.putValue(name, value);
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        session.removeAttribute(name);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void removeValue(String name) {
+        session.removeValue(name);
+    }
+
+    @Override
+    public void invalidate() {
+        session.invalidate();
+    }
+
+    @Override
+    public boolean isNew() {
+        return session.isNew();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PartWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PartWrapper.java
new file mode 100644
index 0000000..6092c60
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PartWrapper.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.Part;
+
+/**
+ * Part wrapper
+ */
+public class PartWrapper implements Part {
+
+    private final javax.servlet.http.Part part;
+
+    /**
+     * Create new part
+     * @param p Wrapped part
+     */
+    public PartWrapper(@NotNull final javax.servlet.http.Part p) {
+        this.part = p;
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return this.part.getInputStream();
+    }
+
+    @Override
+    public String getContentType() {
+        return this.part.getContentType();
+    }
+
+    @Override
+    public String getName() {
+        return this.part.getName();
+    }
+
+    @Override
+    public String getSubmittedFileName() {
+        return this.part.getSubmittedFileName();
+    }
+
+    @Override
+    public long getSize() {
+        return this.part.getSize();
+    }
+
+    @Override
+    public void write(String fileName) throws IOException {
+        this.part.write(fileName);
+    }
+
+    @Override
+    public void delete() throws IOException {
+        this.part.delete();
+    }
+
+    @Override
+    public String getHeader(final String name) {
+        return this.part.getHeader(name);
+    }
+
+    @Override
+    public Collection<String> getHeaders(final String name) {
+        return this.part.getHeaders(name);
+    }
+
+    @Override
+    public Collection<String> getHeaderNames() {
+        return this.part.getHeaderNames();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PreprocessorWrapper.java
similarity index 53%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PreprocessorWrapper.java
index 3b210cd..84c1a83 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PreprocessorWrapper.java
@@ -14,26 +14,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.registry;
+package org.apache.felix.http.base.internal.jakartawrappers;
 
-import javax.servlet.http.MappingMatch;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.servlet.whiteboard.Preprocessor;
 
 /**
- * Resolution of a servlet based on the path
+ * Preprocessor wrapper
  */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
-
-    public String[] patterns;
-
-    public String matchedPattern;
-
-    public MappingMatch match;
-
-    public String matchValue;
+public class PreprocessorWrapper
+    extends FilterWrapper
+    implements Preprocessor {
+
+    /**
+     * Create new preprocessor
+     * @param filter wrapped filter
+     */
+    public PreprocessorWrapper(@NotNull final javax.servlet.Filter filter) {
+        super(filter);
+    }
+
+    /**
+     * Get the preprocessor
+     * @return The preprocessor
+     */
+    public org.osgi.service.http.whiteboard.Preprocessor getPreprocessor() {
+        return (org.osgi.service.http.whiteboard.Preprocessor) super.getFilter();
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PushBuilderWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PushBuilderWrapper.java
new file mode 100644
index 0000000..97f2c89
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/PushBuilderWrapper.java
@@ -0,0 +1,116 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.PushBuilder;
+
+/**
+ * Push builder wrapper
+ */
+public class PushBuilderWrapper implements PushBuilder {
+
+    private final javax.servlet.http.PushBuilder builder;
+
+    /**
+     * Create new wrapper
+     * @param c Wrapped builder
+     */
+    public PushBuilderWrapper(@NotNull final javax.servlet.http.PushBuilder c) {
+        this.builder = c;
+    }
+
+    @Override
+    public PushBuilder method(final String method) {
+        this.builder.method(method);
+        return this;
+    }
+
+    @Override
+    public PushBuilder queryString(final String queryString) {
+        this.builder.queryString(queryString);
+        return this;
+    }
+
+    @Override
+    public PushBuilder sessionId(final String sessionId) {
+        this.builder.sessionId(sessionId);
+        return this;
+    }
+
+    @Override
+    public PushBuilder setHeader(final String name, final String value) {
+        this.builder.setHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public PushBuilder addHeader(final String name, final String value) {
+        this.builder.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public PushBuilder removeHeader(final String name) {
+        this.builder.removeHeader(name);
+        return this;
+    }
+
+    @Override
+    public PushBuilder path(final String path) {
+        this.builder.path(path);
+        return this;
+    }
+
+    @Override
+    public void push() {
+        this.builder.push();
+    }
+
+    @Override
+    public String getMethod() {
+        return this.builder.getMethod();
+    }
+
+    @Override
+    public String getQueryString() {
+        return this.builder.getQueryString();
+    }
+
+    @Override
+    public String getSessionId() {
+        return this.builder.getSessionId();
+    }
+
+    @Override
+    public Set<String> getHeaderNames() {
+        return this.builder.getHeaderNames();
+    }
+
+    @Override
+    public String getHeader(final String name) {
+        return this.builder.getHeader(name);
+    }
+
+    @Override
+    public String getPath() {
+        return this.builder.getPath();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ReadListenerWrapper.java
similarity index 51%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
copy to http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ReadListenerWrapper.java
index 22a048d..164e628 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/DefaultHttpContext.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ReadListenerWrapper.java
@@ -14,40 +14,42 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.service;
-
-import org.osgi.service.http.HttpContext;
-import org.osgi.framework.Bundle;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.net.URL;
-
-public final class DefaultHttpContext 
-    implements HttpContext
-{
-    private Bundle bundle;
-
-    public DefaultHttpContext(Bundle bundle)
-    {
-        this.bundle = bundle;
-    }
+package org.apache.felix.http.base.internal.jakartawrappers;
+
+import java.io.IOException;
+
+import org.jetbrains.annotations.NotNull;
 
-    public String getMimeType(String name)
-    {
-        return null;
+import jakarta.servlet.ReadListener;
+
+/**
+ * Read listener
+ */
+public class ReadListenerWrapper implements ReadListener {
+
+    private final javax.servlet.ReadListener listener;
+
+    /**
+     * Create new lister
+     * @param listener Wrapped listener
+     */
+    public ReadListenerWrapper(@NotNull final javax.servlet.ReadListener listener) {
+        this.listener = listener;
     }
 
-    public URL getResource(String name)
-    {
-        if (name.startsWith("/")) {
-            name = name.substring(1);
-        }
+    @Override
+    public void onDataAvailable() throws IOException {
+        listener.onDataAvailable();
+    }
 
-        return this.bundle.getResource(name);
+    @Override
+    public void onAllDataRead() throws IOException {
+        listener.onAllDataRead();
     }
 
-    public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res)
-    {
-        return true;
+    @Override
+    public void onError(Throwable t) {
+        listener.onError(t);
     }
+
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/RequestDispatcherWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/RequestDispatcherWrapper.java
new file mode 100644
index 0000000..7e5a2dd
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/RequestDispatcherWrapper.java
@@ -0,0 +1,62 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * Dispatcher wrapper
+ */
+public class RequestDispatcherWrapper implements RequestDispatcher {
+
+    private final javax.servlet.RequestDispatcher dispatcher;
+
+    /**
+     * Create new dispatcher
+     * @param dispatcher Dispatcher
+     */
+    public RequestDispatcherWrapper(@NotNull javax.servlet.RequestDispatcher dispatcher) {
+        this.dispatcher = dispatcher;
+    }
+
+    @Override
+    public void forward(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
+        try {
+            dispatcher.forward(org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(request),
+                    org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(response));
+        } catch (final javax.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void include(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
+        try {
+            dispatcher.include(org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(request),
+                    org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(response));
+        } catch (final javax.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletConfigWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletConfigWrapper.java
new file mode 100644
index 0000000..881ab60
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletConfigWrapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.Enumeration;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletContext;
+
+/**
+ * Servlet config wrapper
+ */
+public class ServletConfigWrapper implements ServletConfig {
+
+    private final javax.servlet.ServletConfig config;
+
+    /**
+     * Create new servlet config
+     * @param config wrapped servlet config
+     */
+    public ServletConfigWrapper(@NotNull final javax.servlet.ServletConfig config) {
+        this.config = config;
+    }
+
+    @Override
+    public String getServletName() {
+        return config.getServletName();
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return new ServletContextWrapper(config.getServletContext());
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        return config.getInitParameter(name);
+    }
+
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        return config.getInitParameterNames();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletContextHelperWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletContextHelperWrapper.java
new file mode 100644
index 0000000..9a87ba0
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletContextHelperWrapper.java
@@ -0,0 +1,85 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Set;
+
+import org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper;
+import org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.servlet.whiteboard.ServletContextHelper;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * ServletContextHelper wrapper
+ */
+public class ServletContextHelperWrapper extends ServletContextHelper {
+
+    private final org.osgi.service.http.context.ServletContextHelper helper;
+
+    /**
+     * Create new wrapper
+     * @param helper Helper
+     */
+    public ServletContextHelperWrapper(@NotNull final org.osgi.service.http.context.ServletContextHelper helper) {
+        this.helper = helper;
+    }
+
+    @Override
+    public boolean handleSecurity(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+        return helper.handleSecurity((javax.servlet.http.HttpServletRequest)ServletRequestWrapper.getWrapper(request),
+                (javax.servlet.http.HttpServletResponse)ServletResponseWrapper.getWrapper(response));
+    }
+
+    @Override
+    public void finishSecurity(final HttpServletRequest request, final HttpServletResponse response) {
+        helper.finishSecurity((javax.servlet.http.HttpServletRequest)ServletRequestWrapper.getWrapper(request),
+                (javax.servlet.http.HttpServletResponse)ServletResponseWrapper.getWrapper(response));
+    }
+
+    @Override
+    public URL getResource(final String name) {
+        return helper.getResource(name);
+    }
+
+    @Override
+    public String getMimeType(final String name) {
+        return helper.getMimeType(name);
+    }
+
+    @Override
+    public Set<String> getResourcePaths(final String path) {
+        return helper.getResourcePaths(path);
+    }
+
+    @Override
+    public String getRealPath(final String path) {
+        return helper.getRealPath(path);
+    }
+
+    /**
+     * Get the helper
+     * @return The helper
+     */
+    public @NotNull org.osgi.service.http.context.ServletContextHelper getHelper() {
+        return this.helper;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletContextWrapper.java
new file mode 100644
index 0000000..e936fcc
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletContextWrapper.java
@@ -0,0 +1,417 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterRegistration;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRegistration;
+import jakarta.servlet.ServletRegistration.Dynamic;
+import jakarta.servlet.SessionCookieConfig;
+import jakarta.servlet.SessionTrackingMode;
+import jakarta.servlet.descriptor.JspConfigDescriptor;
+
+/**
+ * Servlet context wrapper
+ */
+public class ServletContextWrapper implements ServletContext {
+
+    private final javax.servlet.ServletContext context;
+
+    /**
+     * Create new context
+     * @param c Wrapped context
+     */
+    public ServletContextWrapper(@NotNull final javax.servlet.ServletContext c) {
+        this.context = c;
+    }
+
+    @Override
+    public String getContextPath() {
+        return this.context.getContextPath();
+    }
+
+    @Override
+    public ServletContext getContext(final String uripath) {
+        final javax.servlet.ServletContext c = this.context.getContext(uripath);
+        if ( c != null ) {
+            return new ServletContextWrapper(c);
+        }
+        return null;
+    }
+
+    @Override
+    public int getMajorVersion() {
+        return this.context.getMajorVersion();
+    }
+
+    @Override
+    public int getMinorVersion() {
+        return this.context.getMinorVersion();
+    }
+
+    @Override
+    public int getEffectiveMajorVersion() {
+        return this.context.getEffectiveMajorVersion();
+    }
+
+    @Override
+    public int getEffectiveMinorVersion() {
+        return this.context.getEffectiveMinorVersion();
+    }
+
+    @Override
+    public String getMimeType(final String file) {
+        return this.context.getMimeType(file);
+    }
+
+    @Override
+    public Set<String> getResourcePaths(final String path) {
+        return this.context.getResourcePaths(path);
+    }
+
+    @Override
+    public URL getResource(final String path) throws MalformedURLException {
+        return this.context.getResource(path);
+    }
+
+    @Override
+    public InputStream getResourceAsStream(final String path) {
+        return this.context.getResourceAsStream(path);
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(final String path) {
+        final javax.servlet.RequestDispatcher dispatcher = this.context.getRequestDispatcher(path);
+        if ( dispatcher != null ) {
+            return new RequestDispatcherWrapper(dispatcher);
+        }
+        return null;
+    }
+
+    @Override
+    public RequestDispatcher getNamedDispatcher(final String name) {
+        final javax.servlet.RequestDispatcher dispatcher = this.context.getNamedDispatcher(name);
+        if ( dispatcher != null ) {
+            return new RequestDispatcherWrapper(dispatcher);
+        }
+        return null;
+    }
+
+    @Override
+    public Servlet getServlet(final String name) throws ServletException {
+        return null;
+    }
+
+    @Override
+    public Enumeration<Servlet> getServlets() {
+        return Collections.emptyEnumeration();
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public Enumeration<String> getServletNames() {
+        return this.context.getServletNames();
+    }
+
+    @Override
+    public void log(final String msg) {
+        this.context.log(msg);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void log(final Exception exception, final String msg) {
+        this.context.log(exception, msg);
+    }
+
+    @Override
+    public void log(final String message, final Throwable throwable) {
+        this.context.log(message, throwable);
+    }
+
+    @Override
+    public String getRealPath(final String path) {
+        return this.context.getRealPath(path);
+    }
+
+    @Override
+    public String getServerInfo() {
+        return this.context.getServerInfo();
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        return this.context.getInitParameter(name);
+    }
+
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        return this.context.getInitParameterNames();
+    }
+
+    @Override
+    public boolean setInitParameter(final String name, final String value) {
+        return this.context.setInitParameter(name, value);
+    }
+
+    @Override
+    public Object getAttribute(final String name) {
+        return this.context.getAttribute(name);
+    }
+
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return this.context.getAttributeNames();
+    }
+
+    @Override
+    public void setAttribute(final String name, final Object object) {
+        this.context.setAttribute(name, object);
+    }
+
+    @Override
+    public void removeAttribute(final String name) {
+        this.context.removeAttribute(name);
+    }
+
+    @Override
+    public String getServletContextName() {
+        return this.context.getServletContextName();
+    }
+
+    @Override
+    public ServletRegistration.Dynamic addServlet(final String servletName, final String className) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletRegistration.Dynamic addServlet(final String servletName, final Servlet servlet) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletRegistration.Dynamic addServlet(final String servletName, final Class<? extends Servlet> servletClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends Servlet> T createServlet(final Class<T> clazz) throws ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletRegistration getServletRegistration(final String servletName) {
+        final javax.servlet.ServletRegistration reg = this.context.getServletRegistration(servletName);
+        if ( reg != null ) {
+            return new ServletRegistrationWrapper(reg);
+        }
+        return null;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+        final Map result = new HashMap<>();
+        for(final Map.Entry<String, ? extends javax.servlet.ServletRegistration> e : this.context.getServletRegistrations().entrySet()) {
+            result.put(e.getKey(), new ServletRegistrationWrapper(e.getValue()));
+        }
+        return result;
+    }
+
+    @Override
+    public FilterRegistration.Dynamic addFilter(final String filterName, final String className) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration.Dynamic addFilter(final String filterName, final Filter filter) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration.Dynamic addFilter(final String filterName, final Class<? extends Filter> filterClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends Filter> T createFilter(final Class<T> clazz) throws ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration getFilterRegistration(final String filterName) {
+        return new FilterRegistrationWrapper(this.context.getFilterRegistration(filterName));
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+        final Map result = new HashMap<>();
+        for(final Map.Entry<String, ? extends javax.servlet.FilterRegistration> e : this.context.getFilterRegistrations().entrySet()) {
+            result.put(e.getKey(), new FilterRegistrationWrapper(e.getValue()));
+        }
+        return result;
+    }
+
+    @Override
+    public SessionCookieConfig getSessionCookieConfig() {
+        return new SessionCookieConfigWrapper(this.context.getSessionCookieConfig());
+    }
+
+    @Override
+    public void setSessionTrackingModes(final Set<SessionTrackingMode> sessionTrackingModes) {
+        if ( sessionTrackingModes == null ) {
+            this.context.setSessionTrackingModes(null);
+        } else {
+            final Set<javax.servlet.SessionTrackingMode> modes = new HashSet<>();
+            if ( sessionTrackingModes.contains(SessionTrackingMode.COOKIE)) {
+                modes.add(javax.servlet.SessionTrackingMode.COOKIE);
+            }
+            if ( sessionTrackingModes.contains(SessionTrackingMode.SSL)) {
+                modes.add(javax.servlet.SessionTrackingMode.SSL);
+            }
+            if ( sessionTrackingModes.contains(SessionTrackingMode.URL)) {
+                modes.add(javax.servlet.SessionTrackingMode.URL);
+            }
+            this.context.setSessionTrackingModes(modes);
+        }
+    }
+
+    @Override
+    public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+        final Set<javax.servlet.SessionTrackingMode> sessionTrackingModes = this.context.getDefaultSessionTrackingModes();
+        final Set<SessionTrackingMode> modes = new HashSet<>();
+        if ( sessionTrackingModes.contains(javax.servlet.SessionTrackingMode.COOKIE)) {
+            modes.add(SessionTrackingMode.COOKIE);
+        }
+        if ( sessionTrackingModes.contains(javax.servlet.SessionTrackingMode.SSL)) {
+            modes.add(SessionTrackingMode.SSL);
+        }
+        if ( sessionTrackingModes.contains(javax.servlet.SessionTrackingMode.URL)) {
+            modes.add(SessionTrackingMode.URL);
+        }
+        return modes;
+    }
+
+    @Override
+    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+        final Set<javax.servlet.SessionTrackingMode> sessionTrackingModes = this.context.getEffectiveSessionTrackingModes();
+        final Set<SessionTrackingMode> modes = new HashSet<>();
+        if ( sessionTrackingModes.contains(javax.servlet.SessionTrackingMode.COOKIE)) {
+            modes.add(SessionTrackingMode.COOKIE);
+        }
+        if ( sessionTrackingModes.contains(javax.servlet.SessionTrackingMode.SSL)) {
+            modes.add(SessionTrackingMode.SSL);
+        }
+        if ( sessionTrackingModes.contains(javax.servlet.SessionTrackingMode.URL)) {
+            modes.add(SessionTrackingMode.URL);
+        }
+        return modes;
+    }
+
+    @Override
+    public void addListener(String className) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends EventListener> void addListener(final T t) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addListener(final Class<? extends EventListener> listenerClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends EventListener> T createListener(final Class<T> clazz) throws ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public JspConfigDescriptor getJspConfigDescriptor() {
+        return null;
+    }
+
+    @Override
+    public ClassLoader getClassLoader() {
+        return this.context.getClassLoader();
+    }
+
+    @Override
+    public void declareRoles(final String... roleNames) {
+        this.context.declareRoles(roleNames);
+    }
+
+    @Override
+    public String getVirtualServerName() {
+        return this.context.getVirtualServerName();
+    }
+
+    @Override
+    public Dynamic addJspFile(final String servletName, final String jspFile) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getSessionTimeout() {
+        return this.context.getSessionTimeout();
+    }
+
+    @Override
+    public void setSessionTimeout(int sessionTimeout) {
+        this.context.setSessionTimeout(sessionTimeout);
+    }
+
+    @Override
+    public String getRequestCharacterEncoding() {
+        return this.context.getRequestCharacterEncoding();
+    }
+
+    @Override
+    public void setRequestCharacterEncoding(final String encoding) {
+        this.context.setRequestCharacterEncoding(encoding);
+    }
+
+    @Override
+    public String getResponseCharacterEncoding() {
+        return this.context.getResponseCharacterEncoding();
+    }
+
+    @Override
+    public void setResponseCharacterEncoding(final String encoding) {
+        this.context.setResponseCharacterEncoding(encoding);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletExceptionUtil.java
similarity index 53%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletExceptionUtil.java
index 3b210cd..b55a604 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletExceptionUtil.java
@@ -14,26 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.registry;
+package org.apache.felix.http.base.internal.jakartawrappers;
 
-import javax.servlet.http.MappingMatch;
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletException;
 
 /**
- * Resolution of a servlet based on the path
+ * Helper class to wrap servlet exceptions
  */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
-
-    public String[] patterns;
-
-    public String matchedPattern;
-
-    public MappingMatch match;
+public class ServletExceptionUtil {
+
+    /**
+     * Throw jakarta servlet exception
+     * @param e javax exception
+     * @return The exception
+     */
+    public static ServletException getServletException(@NotNull final javax.servlet.ServletException e) {
+        if ( e instanceof org.apache.felix.http.base.internal.javaxwrappers.ServletExceptionWrapper) {
+            return ((org.apache.felix.http.base.internal.javaxwrappers.ServletExceptionWrapper)e).getException();
+        }
+        return new ServletExceptionWrapper(e);
+    }
 
-    public String matchValue;
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletExceptionWrapper.java
similarity index 52%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletExceptionWrapper.java
index 3b210cd..cc835a2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletExceptionWrapper.java
@@ -14,26 +14,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.registry;
+package org.apache.felix.http.base.internal.jakartawrappers;
 
-import javax.servlet.http.MappingMatch;
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletException;
 
 /**
- * Resolution of a servlet based on the path
+ * Wrapper for servlet exception
  */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
-
-    public String[] patterns;
-
-    public String matchedPattern;
-
-    public MappingMatch match;
-
-    public String matchValue;
+public class ServletExceptionWrapper extends ServletException {
+
+    private static final long serialVersionUID = 1L;
+
+    private final javax.servlet.ServletException exception;
+
+    /**
+     * Create new wrapepr exception
+     * @param e Original exception
+     */
+    public ServletExceptionWrapper(@NotNull final javax.servlet.ServletException e) {
+        this.exception = e;
+    }
+
+    /**
+     * Get the original exception
+     * @return The original exception
+     */
+    @NotNull public javax.servlet.ServletException getException() {
+        return this.exception;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletInputStreamWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletInputStreamWrapper.java
new file mode 100644
index 0000000..8191f5c
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletInputStreamWrapper.java
@@ -0,0 +1,128 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+
+/**
+ * Servlet input stream wrapper
+ */
+public class ServletInputStreamWrapper extends ServletInputStream {
+
+    private final javax.servlet.ServletInputStream stream;
+
+    /**
+     * Create input stream
+     * @param stream Wrapped stream
+     */
+    public ServletInputStreamWrapper(@NotNull final javax.servlet.ServletInputStream stream) {
+        this.stream = stream;
+    }
+
+    @Override
+    public int readLine(final byte[] b, final int off, final int len) throws IOException {
+        return this.stream.readLine(b, off, len);
+    }
+
+    @Override
+    public boolean isFinished() {
+        return this.stream.isFinished();
+    }
+
+    @Override
+    public boolean isReady() {
+        return this.stream.isReady();
+    }
+
+    @Override
+    public void setReadListener(final ReadListener readListener) {
+        this.stream.setReadListener(new org.apache.felix.http.base.internal.javaxwrappers.ReadListenerWrapper(readListener));
+    }
+
+    @Override
+    public int read() throws IOException {
+        return this.stream.read();
+    }
+
+    @Override
+    public int read(final byte[] b) throws IOException {
+        return this.stream.read(b);
+    }
+
+    @Override
+    public int read(final byte[] b, final int off, final int len) throws IOException {
+        return this.stream.read(b, off, len);
+    }
+
+    @Override
+    public byte[] readAllBytes() throws IOException {
+        return this.stream.readAllBytes();
+    }
+
+    @Override
+    public byte[] readNBytes(final int len) throws IOException {
+        return this.stream.readNBytes(len);
+    }
+
+    @Override
+    public int readNBytes(final byte[] b, final int off, final int len) throws IOException {
+        return this.stream.readNBytes(b, off, len);
+    }
+
+    @Override
+    public long skip(final long n) throws IOException {
+        return this.stream.skip(n);
+    }
+
+    @Override
+    public int available() throws IOException {
+        return this.stream.available();
+    }
+
+    @Override
+    public void close() throws IOException {
+        this.stream.close();
+    }
+
+    @Override
+    public synchronized void mark(final int readlimit) {
+        this.stream.mark(readlimit);
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        this.stream.reset();
+    }
+
+    @Override
+    public boolean markSupported() {
+        return this.stream.markSupported();
+    }
+
+    @Override
+    public long transferTo(final OutputStream out) throws IOException {
+        return this.stream.transferTo(out);
+    }
+
+
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletOutputStreamWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletOutputStreamWrapper.java
new file mode 100644
index 0000000..064fb17
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletOutputStreamWrapper.java
@@ -0,0 +1,150 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
+
+/**
+ * Servlet output stream
+ */
+public class ServletOutputStreamWrapper extends ServletOutputStream {
+
+    private final javax.servlet.ServletOutputStream stream;
+
+    /**
+     * Create new stream
+     * @param stream wrapped stream
+     */
+    public ServletOutputStreamWrapper(@NotNull final javax.servlet.ServletOutputStream stream) {
+        this.stream = stream;
+    }
+
+    @Override
+    public void print(final String s) throws IOException {
+        this.stream.print(s);
+    }
+
+    @Override
+    public void print(final boolean b) throws IOException {
+        this.stream.print(b);
+    }
+
+    @Override
+    public void print(final char c) throws IOException {
+        this.stream.print(c);
+    }
+
+    @Override
+    public void print(final int i) throws IOException {
+        this.stream.print(i);
+    }
+
+    @Override
+    public void print(final long l) throws IOException {
+        this.stream.print(l);
+    }
+
+    @Override
+    public void print(final float f) throws IOException {
+        this.stream.print(f);
+    }
+
+    @Override
+    public void print(final double d) throws IOException {
+        this.stream.print(d);
+    }
+
+    @Override
+    public void println() throws IOException {
+        this.stream.println();
+    }
+
+    @Override
+    public void println(final String s) throws IOException {
+        this.stream.println(s);
+    }
+
+    @Override
+    public void println(final boolean b) throws IOException {
+        this.stream.println(b);
+    }
+
+    @Override
+    public void println(final char c) throws IOException {
+        this.stream.println(c);
+    }
+
+    @Override
+    public void println(final int i) throws IOException {
+        this.stream.println(i);
+    }
+
+    @Override
+    public void println(final long l) throws IOException {
+        this.stream.println(l);
+    }
+
+    @Override
+    public void println(final float f) throws IOException {
+        this.stream.println(f);
+    }
+
+    @Override
+    public void println(final double d) throws IOException {
+        this.stream.println(d);
+    }
+
+    @Override
+    public boolean isReady() {
+        return this.stream.isReady();
+    }
+
+    @Override
+    public void setWriteListener(final WriteListener writeListener) {
+        this.stream.setWriteListener(new org.apache.felix.http.base.internal.javaxwrappers.WriteListenerWrapper(writeListener));
+    }
+
+    @Override
+    public void write(final int b) throws IOException {
+        this.stream.write(b);
+    }
+
+    @Override
+    public void write(final byte[] b) throws IOException {
+        this.stream.write(b);
+    }
+
+    @Override
+    public void write(final byte[] b, final int off, final int len) throws IOException {
+        this.stream.write(b, off, len);
+    }
+
+    @Override
+    public void flush() throws IOException {
+        this.stream.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        this.stream.close();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletRegistrationWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletRegistrationWrapper.java
new file mode 100644
index 0000000..4381a73
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletRegistrationWrapper.java
@@ -0,0 +1,86 @@
+/*
+ * 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.jakartawrappers;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletRegistration;
+
+/**
+ * servlet registration wrapper
+ */
+public class ServletRegistrationWrapper implements ServletRegistration {
+
+    private final javax.servlet.ServletRegistration reg;
+
+    /**
+     * Create new wrapper
+     * @param c Wrapped registration
+     */
+    public ServletRegistrationWrapper(@NotNull final javax.servlet.ServletRegistration c) {
+        this.reg = c;
+    }
+
+    @Override
+    public Set<String> addMapping(final String... urlPatterns) {
+        return reg.addMapping(urlPatterns);
+    }
+
+    @Override
+    public String getName() {
+        return reg.getName();
+    }
+
+    @Override
+    public Collection<String> getMappings() {
+        return reg.getMappings();
+    }
+
+    @Override
+    public String getClassName() {
+        return reg.getClassName();
+    }
+
+    @Override
+    public boolean setInitParameter(final String name, final String value) {
+        return reg.setInitParameter(name, value);
+    }
+
+    @Override
+    public String getRunAsRole() {
+        return reg.getRunAsRole();
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        return reg.getInitParameter(name);
+    }
+
+    @Override
+    public Set<String> setInitParameters(final Map<String, String> initParameters) {
+        return reg.setInitParameters(initParameters);
+    }
+
+    @Override
+    public Map<String, String> getInitParameters() {
+        return reg.getInitParameters();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletRequestWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletRequestWrapper.java
new file mode 100644
index 0000000..0d42f91
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletRequestWrapper.java
@@ -0,0 +1,381 @@
+/*
+ * 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.jakartawrappers;
+
+import static jakarta.servlet.AsyncContext.ASYNC_CONTEXT_PATH;
+import static jakarta.servlet.AsyncContext.ASYNC_MAPPING;
+import static jakarta.servlet.AsyncContext.ASYNC_PATH_INFO;
+import static jakarta.servlet.AsyncContext.ASYNC_QUERY_STRING;
+import static jakarta.servlet.AsyncContext.ASYNC_REQUEST_URI;
+import static jakarta.servlet.AsyncContext.ASYNC_SERVLET_PATH;
+import static jakarta.servlet.RequestDispatcher.ERROR_EXCEPTION;
+import static jakarta.servlet.RequestDispatcher.ERROR_EXCEPTION_TYPE;
+import static jakarta.servlet.RequestDispatcher.ERROR_MESSAGE;
+import static jakarta.servlet.RequestDispatcher.ERROR_REQUEST_URI;
+import static jakarta.servlet.RequestDispatcher.ERROR_SERVLET_NAME;
+import static jakarta.servlet.RequestDispatcher.ERROR_STATUS_CODE;
+import static jakarta.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH;
+import static jakarta.servlet.RequestDispatcher.FORWARD_MAPPING;
+import static jakarta.servlet.RequestDispatcher.FORWARD_PATH_INFO;
+import static jakarta.servlet.RequestDispatcher.FORWARD_QUERY_STRING;
+import static jakarta.servlet.RequestDispatcher.FORWARD_REQUEST_URI;
+import static jakarta.servlet.RequestDispatcher.FORWARD_SERVLET_PATH;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_MAPPING;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_PATH_INFO;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_QUERY_STRING;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_REQUEST_URI;
+import static jakarta.servlet.RequestDispatcher.INCLUDE_SERVLET_PATH;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * Servlet request wrapper
+ */
+public class ServletRequestWrapper implements ServletRequest {
+
+    private final javax.servlet.ServletRequest request;
+
+    /**
+     * Get the wrapper
+     * @param r The request
+     * @return The wrapped request
+     */
+    public static ServletRequest getWrapper(final javax.servlet.ServletRequest r) {
+        if ( r instanceof org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper) {
+            return ((org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper)r).getRequest();
+        }
+        if ( r instanceof javax.servlet.http.HttpServletRequest ) {
+            return new HttpServletRequestWrapper((javax.servlet.http.HttpServletRequest)r);
+        }
+        return new ServletRequestWrapper(r);
+    }
+
+    /**
+     * Create a wrapper
+     * @param r The wrapped request
+     */
+    public ServletRequestWrapper(@NotNull final javax.servlet.ServletRequest r) {
+        this.request = r;
+    }
+
+
+    /**
+     * Get the request
+     * @return The request
+     */
+    public javax.servlet.ServletRequest getRequest() {
+        return this.request;
+    }
+
+    private Object wrapHttpServletMapping(final Object value) {
+        if ( value instanceof org.apache.felix.http.base.internal.javaxwrappers.HttpServletMappingWrapper ) {
+            return ((org.apache.felix.http.base.internal.javaxwrappers.HttpServletMappingWrapper)value).getMapping();
+        }
+        if ( value instanceof javax.servlet.http.HttpServletMapping ) {
+            return new HttpServletMappingWrapper((javax.servlet.http.HttpServletMapping)value);
+        }
+        return value;
+    }
+
+    @Override
+    public Object getAttribute(final String name) {
+        if ( FORWARD_CONTEXT_PATH.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH);
+
+        } else if ( FORWARD_MAPPING.equals(name) ) {
+            return wrapHttpServletMapping(this.request.getAttribute(javax.servlet.RequestDispatcher.FORWARD_MAPPING));
+
+        } else if ( FORWARD_PATH_INFO.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.FORWARD_PATH_INFO);
+
+        } else if ( FORWARD_QUERY_STRING.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.FORWARD_QUERY_STRING);
+
+        } else if ( FORWARD_REQUEST_URI.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.FORWARD_REQUEST_URI);
+
+        } else if ( FORWARD_SERVLET_PATH.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.FORWARD_SERVLET_PATH);
+
+        } else if ( INCLUDE_CONTEXT_PATH.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH);
+
+        } else if ( INCLUDE_MAPPING.equals(name) ) {
+            return wrapHttpServletMapping(this.request.getAttribute(javax.servlet.RequestDispatcher.INCLUDE_MAPPING));
+
+        } else if ( INCLUDE_PATH_INFO.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.INCLUDE_PATH_INFO);
+
+        } else if ( INCLUDE_QUERY_STRING.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.INCLUDE_QUERY_STRING);
+
+        } else if ( INCLUDE_REQUEST_URI.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.INCLUDE_REQUEST_URI);
+
+        } else if ( INCLUDE_SERVLET_PATH.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.INCLUDE_SERVLET_PATH);
+
+        } else if ( ERROR_EXCEPTION.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.ERROR_EXCEPTION);
+
+        } else if ( ERROR_EXCEPTION_TYPE.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.ERROR_EXCEPTION_TYPE);
+
+        } else if ( ERROR_MESSAGE.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.ERROR_MESSAGE);
+
+        } else if ( ERROR_REQUEST_URI.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.ERROR_REQUEST_URI);
+
+        } else if ( ERROR_SERVLET_NAME.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.ERROR_SERVLET_NAME);
+
+        } else if ( ERROR_STATUS_CODE.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.RequestDispatcher.ERROR_STATUS_CODE);
+
+        } else if ( ASYNC_CONTEXT_PATH.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.AsyncContext.ASYNC_CONTEXT_PATH);
+
+        } else if ( ASYNC_MAPPING.equals(name) ) {
+            return wrapHttpServletMapping(this.request.getAttribute(javax.servlet.AsyncContext.ASYNC_MAPPING));
+
+        } else if ( ASYNC_PATH_INFO.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.AsyncContext.ASYNC_PATH_INFO);
+
+        } else if ( ASYNC_QUERY_STRING.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.AsyncContext.ASYNC_QUERY_STRING);
+
+        } else if ( ASYNC_REQUEST_URI.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.AsyncContext.ASYNC_REQUEST_URI);
+
+        } else if ( ASYNC_SERVLET_PATH.equals(name) ) {
+            return this.request.getAttribute(javax.servlet.AsyncContext.ASYNC_SERVLET_PATH);
+        }
+        return this.request.getAttribute(name);
+    }
+
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return this.request.getAttributeNames();
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return this.request.getCharacterEncoding();
+    }
+
+    @Override
+    public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+        this.request.setCharacterEncoding(env);
+    }
+
+    @Override
+    public int getContentLength() {
+        return this.request.getContentLength();
+    }
+
+    @Override
+    public long getContentLengthLong() {
+        return this.request.getContentLengthLong();
+    }
+
+    @Override
+    public String getContentType() {
+        return this.request.getContentType();
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        return new ServletInputStreamWrapper(this.request.getInputStream());
+    }
+
+    @Override
+    public String getParameter(String name) {
+        return this.request.getParameter(name);
+    }
+
+    @Override
+    public Enumeration<String> getParameterNames() {
+        return this.request.getParameterNames();
+    }
+
+    @Override
+    public String[] getParameterValues(final String name) {
+        return this.request.getParameterValues(name);
+    }
+
+    @Override
+    public Map<String, String[]> getParameterMap() {
+        return this.request.getParameterMap();
+    }
+
+    @Override
+    public String getProtocol() {
+        return this.request.getProtocol();
+    }
+
+    @Override
+    public String getScheme() {
+        return this.request.getScheme();
+    }
+
+    @Override
+    public String getServerName() {
+        return this.request.getServerName();
+    }
+
+    @Override
+    public int getServerPort() {
+        return this.request.getServerPort();
+    }
+
+    @Override
+    public BufferedReader getReader() throws IOException {
+        return this.request.getReader();
+    }
+
+    @Override
+    public String getRemoteAddr() {
+        return this.request.getRemoteAddr();
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return this.request.getRemoteHost();
+    }
+
+    @Override
+    public void setAttribute(final String name, final Object o) {
+        this.request.setAttribute(name, o);
+    }
+
+    @Override
+    public void removeAttribute(final String name) {
+        this.request.removeAttribute(name);
+    }
+
+    @Override
+    public Locale getLocale() {
+        return this.request.getLocale();
+    }
+
+    @Override
+    public Enumeration<Locale> getLocales() {
+        return this.request.getLocales();
+    }
+
+    @Override
+    public boolean isSecure() {
+        return this.request.isSecure();
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(final String path) {
+        final javax.servlet.RequestDispatcher dispatcher = this.request.getRequestDispatcher(path);
+        if ( dispatcher != null ) {
+            return new RequestDispatcherWrapper(dispatcher);
+        }
+        return null;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public String getRealPath(final String path) {
+        return this.request.getRealPath(path);
+    }
+
+    @Override
+    public int getRemotePort() {
+        return this.request.getRemotePort();
+    }
+
+    @Override
+    public String getLocalName() {
+        return this.request.getLocalName();
+    }
+
+    @Override
+    public String getLocalAddr() {
+        return this.request.getLocalAddr();
+    }
+
+    @Override
+    public int getLocalPort() {
+        return this.request.getLocalPort();
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return new ServletContextWrapper(this.request.getServletContext());
+    }
+
+    @Override
+    public AsyncContext startAsync() throws IllegalStateException {
+        return new AsyncContextWrapper(this.request.startAsync());
+    }
+
+    @Override
+    public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
+            throws IllegalStateException {
+        return new AsyncContextWrapper(this.request.startAsync(
+                org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(servletRequest),
+                org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(servletResponse)));
+    }
+
+    @Override
+    public boolean isAsyncStarted() {
+        return this.request.isAsyncStarted();
+    }
+
+    @Override
+    public boolean isAsyncSupported() {
+        return this.request.isAsyncSupported();
+    }
+
+    @Override
+    public AsyncContext getAsyncContext() {
+        return new AsyncContextWrapper(this.request.getAsyncContext());
+    }
+
+    @Override
+    public DispatcherType getDispatcherType() {
+        switch (this.request.getDispatcherType()) {
+        case ASYNC : return DispatcherType.ASYNC;
+        case ERROR : return DispatcherType.ERROR;
+        case FORWARD : return DispatcherType.FORWARD;
+        case INCLUDE : return DispatcherType.INCLUDE;
+        case REQUEST : return DispatcherType.REQUEST;
+        }
+        return null;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletResponseWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletResponseWrapper.java
new file mode 100644
index 0000000..6778578
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletResponseWrapper.java
@@ -0,0 +1,145 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * Servlet response wrapper
+ */
+public class ServletResponseWrapper implements ServletResponse {
+
+    private final javax.servlet.ServletResponse response;
+
+    /**
+     * Get a wrapper
+     * @param r Response
+     * @return Wrapped response
+     */
+    public static ServletResponse getWrapper(final javax.servlet.ServletResponse r) {
+        if ( r instanceof org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper) {
+            return ((org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper)r).getResponse();
+        }
+        if ( r instanceof javax.servlet.http.HttpServletResponse ) {
+            return new HttpServletResponseWrapper((javax.servlet.http.HttpServletResponse)r);
+        }
+        return new ServletResponseWrapper(r);
+    }
+
+    /**
+     * Create new response
+     * @param r Wrapped response
+     */
+    public ServletResponseWrapper(@NotNull final javax.servlet.ServletResponse r) {
+        this.response = r;
+    }
+
+    /**
+     * Get the wrapped response
+     * @return The response
+     */
+    public javax.servlet.ServletResponse getResponse() {
+        return this.response;
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return this.response.getCharacterEncoding();
+    }
+
+    @Override
+    public String getContentType() {
+        return this.response.getContentType();
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() throws IOException {
+        return new ServletOutputStreamWrapper(this.response.getOutputStream());
+    }
+
+    @Override
+    public PrintWriter getWriter() throws IOException {
+        return this.response.getWriter();
+    }
+
+    @Override
+    public void setCharacterEncoding(final String charset) {
+        this.response.setCharacterEncoding(charset);
+    }
+
+    @Override
+    public void setContentLength(final int len) {
+        this.response.setContentLength(len);
+    }
+
+    @Override
+    public void setContentLengthLong(final long len) {
+        this.response.setContentLengthLong(len);
+    }
+
+    @Override
+    public void setContentType(final String type) {
+        this.response.setContentType(type);
+    }
+
+    @Override
+    public void setBufferSize(final int size) {
+        this.response.setBufferSize(size);
+    }
+
+    @Override
+    public int getBufferSize() {
+        return this.response.getBufferSize();
+    }
+
+    @Override
+    public void flushBuffer() throws IOException {
+        this.response.flushBuffer();
+    }
+
+    @Override
+    public void resetBuffer() {
+        this.response.resetBuffer();
+    }
+
+    @Override
+    public boolean isCommitted() {
+        return this.response.isCommitted();
+    }
+
+    @Override
+    public void reset() {
+        this.response.reset();
+    }
+
+    @Override
+    public void setLocale(final Locale loc) {
+        this.response.setLocale(loc);
+    }
+
+    @Override
+    public Locale getLocale() {
+        return this.response.getLocale();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletWrapper.java
new file mode 100644
index 0000000..3c38b0b
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/ServletWrapper.java
@@ -0,0 +1,98 @@
+/*
+ * 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.jakartawrappers;
+
+import java.io.IOException;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * Servlet wrapper
+ */
+public class ServletWrapper implements Servlet {
+
+    private final javax.servlet.Servlet servlet;
+
+    /**
+     * Get the registered servlet
+     * @param s The servlet
+     * @return The registered servlet
+     */
+    public static Servlet getRegisteredServlet(final javax.servlet.Servlet s) {
+        if ( s instanceof org.apache.felix.http.base.internal.javaxwrappers.ServletWrapper ) {
+            return ((org.apache.felix.http.base.internal.javaxwrappers.ServletWrapper)s).getServlet();
+        }
+        return new ServletWrapper(s);
+    }
+
+    /**
+     * Create new servlet
+     * @param servlet wrapped servlet
+     */
+    public ServletWrapper(@NotNull final javax.servlet.Servlet servlet) {
+        this.servlet = servlet;
+    }
+
+    @Override
+    public void init(final ServletConfig config) throws ServletException {
+        try {
+            servlet.init(new org.apache.felix.http.base.internal.javaxwrappers.ServletConfigWrapper(config));
+        } catch (javax.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public ServletConfig getServletConfig() {
+        return new ServletConfigWrapper(servlet.getServletConfig());
+    }
+
+    @Override
+    public void service(final ServletRequest req, final ServletResponse res)
+            throws ServletException, IOException {
+        try {
+            servlet.service(org.apache.felix.http.base.internal.javaxwrappers.ServletRequestWrapper.getWrapper(req),
+                    org.apache.felix.http.base.internal.javaxwrappers.ServletResponseWrapper.getWrapper(res));
+        } catch (javax.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public String getServletInfo() {
+        return servlet.getServletInfo();
+    }
+
+    @Override
+    public void destroy() {
+        servlet.destroy();
+    }
+
+    /**
+     * Get the wrapped servlet
+     * @return The servlet
+     */
+    public @NotNull javax.servlet.Servlet getServlet() {
+        return this.servlet;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/SessionCookieConfigWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/SessionCookieConfigWrapper.java
new file mode 100644
index 0000000..50f77dc
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/SessionCookieConfigWrapper.java
@@ -0,0 +1,107 @@
+/*
+ * 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.jakartawrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.SessionCookieConfig;
+
+/**
+ * Session cookie config wrapper
+ */
+public class SessionCookieConfigWrapper implements SessionCookieConfig {
+
+    private final javax.servlet.SessionCookieConfig config;
+
+    /**
+     * Create new config
+     * @param c Wrapped config
+     */
+    public SessionCookieConfigWrapper(@NotNull final javax.servlet.SessionCookieConfig c) {
+        this.config = c;
+    }
+
+    @Override
+    public void setName(String name) {
+        config.setName(name);
+    }
+
+    @Override
+    public String getName() {
+        return config.getName();
+    }
+
+    @Override
+    public void setDomain(final String domain) {
+        config.setDomain(domain);
+    }
+
+    @Override
+    public String getDomain() {
+        return config.getDomain();
+    }
+
+    @Override
+    public void setPath(final String path) {
+        config.setPath(path);
+    }
+
+    @Override
+    public String getPath() {
+        return config.getPath();
+    }
+
+    @Override
+    public void setComment(final String comment) {
+        config.setComment(comment);
+    }
+
+    @Override
+    public String getComment() {
+        return config.getComment();
+    }
+
+    @Override
+    public void setHttpOnly(final boolean httpOnly) {
+        config.setHttpOnly(httpOnly);
+    }
+
+    @Override
+    public boolean isHttpOnly() {
+        return config.isHttpOnly();
+    }
+
+    @Override
+    public void setSecure(final boolean secure) {
+        config.setSecure(secure);
+    }
+
+    @Override
+    public boolean isSecure() {
+        return config.isSecure();
+    }
+
+    @Override
+    public void setMaxAge(final int maxAge) {
+        config.setMaxAge(maxAge);
+    }
+
+    @Override
+    public int getMaxAge() {
+        return config.getMaxAge();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/WriteListenerWrapper.java
similarity index 53%
copy from http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
copy to http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/WriteListenerWrapper.java
index 3b210cd..3f5d673 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/jakartawrappers/WriteListenerWrapper.java
@@ -14,26 +14,36 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.http.base.internal.registry;
+package org.apache.felix.http.base.internal.jakartawrappers;
 
-import javax.servlet.http.MappingMatch;
+import java.io.IOException;
 
-/**
- * Resolution of a servlet based on the path
- */
-public class PathResolution extends ServletResolution {
-
-    public String servletPath;
-
-    public String pathInfo;
-
-    public String requestURI;
+import org.jetbrains.annotations.NotNull;
 
-    public String[] patterns;
+import jakarta.servlet.WriteListener;
 
-    public String matchedPattern;
-
-    public MappingMatch match;
-
-    public String matchValue;
+/**
+ * Write listener
+ */
+public class WriteListenerWrapper implements WriteListener {
+
+    private final javax.servlet.WriteListener listener;
+
+    /**
+     * Create new lister
+     * @param listener Wrapped listener
+     */
+    public WriteListenerWrapper(@NotNull final javax.servlet.WriteListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public void onWritePossible() throws IOException {
+        listener.onWritePossible();
+    }
+
+    @Override
+    public void onError(final Throwable t) {
+        listener.onError(t);
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/AsyncContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/AsyncContextWrapper.java
new file mode 100644
index 0000000..470034e
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/AsyncContextWrapper.java
@@ -0,0 +1,104 @@
+/*
+ * 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.javaxwrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.AsyncContext;
+
+/**
+ * async context wrapper
+ */
+public class AsyncContextWrapper implements javax.servlet.AsyncContext {
+
+    private final AsyncContext context;
+
+    /**
+     * Create new context
+     * @param c Wrapped context
+     */
+    public AsyncContextWrapper(@NotNull final AsyncContext c) {
+        this.context = c;
+    }
+
+    @Override
+    public javax.servlet.ServletRequest getRequest() {
+        return ServletRequestWrapper.getWrapper(context.getRequest());
+    }
+
+    @Override
+    public javax.servlet.ServletResponse getResponse() {
+        return ServletResponseWrapper.getWrapper(context.getResponse());
+    }
+
+    @Override
+    public boolean hasOriginalRequestAndResponse() {
+        return context.hasOriginalRequestAndResponse();
+    }
+
+    @Override
+    public void dispatch() {
+        context.dispatch();
+    }
+
+    @Override
+    public void dispatch(final String path) {
+        context.dispatch(path);
+    }
+
+    @Override
+    public void dispatch(final javax.servlet.ServletContext sc, final String path) {
+        context.dispatch(new org.apache.felix.http.base.internal.jakartawrappers.ServletContextWrapper(sc), path);
+    }
+
+    @Override
+    public void complete() {
+        context.complete();
+    }
+
+    @Override
+    public void start(final Runnable run) {
+        context.start(run);
+    }
+
+    @Override
+    public void addListener(final javax.servlet.AsyncListener listener) {
+        context.addListener(new org.apache.felix.http.base.internal.jakartawrappers.AsyncListenerWrapper(listener));
+    }
+
+    @Override
+    public void addListener(final javax.servlet.AsyncListener listener, javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) {
+        context.addListener(new org.apache.felix.http.base.internal.jakartawrappers.AsyncListenerWrapper(listener),
+                org.apache.felix.http.base.internal.jakartawrappers.ServletRequestWrapper.getWrapper(servletRequest),
+                org.apache.felix.http.base.internal.jakartawrappers.ServletResponseWrapper.getWrapper(servletResponse));
+    }
+
+    @Override
+    public <T extends javax.servlet.AsyncListener> T createListener(final Class<T> clazz) throws javax.servlet.ServletException {
+        throw new javax.servlet.ServletException();
+    }
+
+    @Override
+    public void setTimeout(final long timeout) {
+        context.setTimeout(timeout);
+    }
+
+    @Override
+    public long getTimeout() {
+        return context.getTimeout();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/AsyncListenerWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/AsyncListenerWrapper.java
new file mode 100644
index 0000000..d709bc4
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/AsyncListenerWrapper.java
@@ -0,0 +1,78 @@
+/*
+ * 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.javaxwrappers;
+
+import java.io.IOException;
+
+import org.apache.felix.http.base.internal.jakartawrappers.ServletRequestWrapper;
+import org.apache.felix.http.base.internal.jakartawrappers.ServletResponseWrapper;
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+
+/**
+ * Async listener wrapper
+ */
+public class AsyncListenerWrapper implements javax.servlet.AsyncListener {
+
+    private final AsyncListener listener;
+
+    /**
+     * Create new listener
+     * @param c Wrapped listener
+     */
+    public AsyncListenerWrapper(@NotNull final AsyncListener c) {
+        this.listener = c;
+    }
+
+    @Override
+    public void onComplete(final javax.servlet.AsyncEvent event) throws IOException {
+        this.listener.onComplete(new AsyncEvent(
+                new org.apache.felix.http.base.internal.jakartawrappers.AsyncContextWrapper(event.getAsyncContext()),
+                ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+
+    @Override
+    public void onTimeout(final javax.servlet.AsyncEvent event) throws IOException {
+        this.listener.onTimeout(new AsyncEvent(
+                new org.apache.felix.http.base.internal.jakartawrappers.AsyncContextWrapper(event.getAsyncContext()),
+                ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+
+    @Override
+    public void onError(final javax.servlet.AsyncEvent event) throws IOException {
+        this.listener.onError(new AsyncEvent(
+                new org.apache.felix.http.base.internal.jakartawrappers.AsyncContextWrapper(event.getAsyncContext()),
+                ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+
+    @Override
+    public void onStartAsync(final javax.servlet.AsyncEvent event) throws IOException {
+        this.listener.onStartAsync(new AsyncEvent(
+                new org.apache.felix.http.base.internal.jakartawrappers.AsyncContextWrapper(event.getAsyncContext()),
+                ServletRequestWrapper.getWrapper(event.getSuppliedRequest()),
+                ServletResponseWrapper.getWrapper(event.getSuppliedResponse()),
+                event.getThrowable()));
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/CookieWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/CookieWrapper.java
new file mode 100644
index 0000000..38db88d
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/CookieWrapper.java
@@ -0,0 +1,111 @@
+/*
+ * 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.javaxwrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.Cookie;
+
+/**
+ * Javax cookie based on a jakarta cookie
+ */
+public class CookieWrapper extends javax.servlet.http.Cookie {
+
+    private static final long serialVersionUID = -6762987885237379239L;
+
+    /**
+     * Wrap an array of cookies
+     * @param array The array
+     * @return The result
+     */
+    public static javax.servlet.http.Cookie[] wrap(final Cookie[] array) {
+        if ( array == null ) {
+            return null;
+        }
+        final javax.servlet.http.Cookie[] result = new javax.servlet.http.Cookie[array.length];
+        for(int i=0;i<array.length;i++) {
+            result[i] = new CookieWrapper(array[i]);
+        }
+        return result;
+    }
+
+    private final Cookie cookie;
+
+    /**
+     * Create new cookie
+     * @param c Wrapped cookie
+     */
+    public CookieWrapper(@NotNull final Cookie c) {
+        super(c.getName(), c.getValue());
+        this.cookie = c;
+        super.setComment(c.getComment());
+        super.setDomain(c.getDomain());
+        super.setHttpOnly(c.isHttpOnly());
+        super.setMaxAge(c.getMaxAge());
+        super.setPath(c.getPath());
+        super.setSecure(c.getSecure());
+        super.setVersion(c.getVersion());
+    }
+
+    @Override
+    public void setComment(final String purpose) {
+        this.cookie.setComment(purpose);
+        super.setComment(purpose);
+    }
+
+    @Override
+    public void setDomain(final String domain) {
+        this.cookie.setDomain(domain);
+        super.setDomain(domain);
+    }
+
+    @Override
+    public void setMaxAge(final int expiry) {
+        this.cookie.setMaxAge(expiry);
+        super.setMaxAge(expiry);
+    }
+
+    @Override
+    public void setPath(final String uri) {
+        this.cookie.setPath(uri);
+        super.setPath(uri);
+    }
+
+    @Override
+    public void setSecure(final boolean flag) {
+        this.cookie.setSecure(flag);
+        super.setSecure(flag);
+    }
+
+    @Override
+    public void setValue(final String newValue) {
+        this.cookie.setValue(newValue);
+        super.setValue(newValue);
+    }
+
+    @Override
+    public void setVersion(final int v) {
+        this.cookie.setVersion(v);
+        super.setVersion(v);
+    }
+
+    @Override
+    public void setHttpOnly(final boolean isHttpOnly) {
+        this.cookie.setHttpOnly(isHttpOnly);
+        super.setHttpOnly(isHttpOnly);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterChainWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterChainWrapper.java
new file mode 100644
index 0000000..6d7d5d0
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterChainWrapper.java
@@ -0,0 +1,51 @@
+/*
+ * 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.javaxwrappers;
+
+import java.io.IOException;
+
+import org.apache.felix.http.base.internal.jakartawrappers.ServletResponseWrapper;
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.FilterChain;
+
+/**
+ * Javax filter chain based on a jakarta filter chain
+ */
+public class FilterChainWrapper implements javax.servlet.FilterChain {
+
+    private final FilterChain filterChain;
+
+    /**
+     * Create new chain
+     * @param chain Wrapped chain
+     */
+    public FilterChainWrapper(@NotNull final FilterChain chain) {
+        this.filterChain = chain;
+    }
+
+    @Override
+    public void doFilter(final javax.servlet.ServletRequest request, final javax.servlet.ServletResponse response)
+            throws IOException, javax.servlet.ServletException {
+        try {
+            filterChain.doFilter(org.apache.felix.http.base.internal.jakartawrappers.ServletRequestWrapper.getWrapper(request),
+                    ServletResponseWrapper.getWrapper(response));
+        } catch (final jakarta.servlet.ServletException e) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterConfigWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterConfigWrapper.java
new file mode 100644
index 0000000..c6ebe17
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterConfigWrapper.java
@@ -0,0 +1,59 @@
+/*
+ * 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.javaxwrappers;
+
+import java.util.Enumeration;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.FilterConfig;
+
+/**
+ * Filter config wrapper
+ */
+public class FilterConfigWrapper implements javax.servlet.FilterConfig {
+
+    private final FilterConfig filterConfig;
+
+    /**
+     * Create config
+     * @param filterConfig wrapped config
+     */
+    public FilterConfigWrapper(@NotNull final FilterConfig filterConfig) {
+        this.filterConfig = filterConfig;
+    }
+
+    @Override
+    public String getFilterName() {
+        return this.filterConfig.getFilterName();
+    }
+
+    @Override
+    public javax.servlet.ServletContext getServletContext() {
+        return new ServletContextWrapper(this.filterConfig.getServletContext());
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        return this.filterConfig.getInitParameter(name);
+    }
+
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        return this.filterConfig.getInitParameterNames();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterRegistrationWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterRegistrationWrapper.java
new file mode 100644
index 0000000..7535f5f
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/FilterRegistrationWrapper.java
@@ -0,0 +1,115 @@
+/*
+ * 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.javaxwrappers;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.FilterRegistration;
+
+/**
+ * Filter registration wrapper
+ */
+public class FilterRegistrationWrapper implements javax.servlet.FilterRegistration {
+
+    private final FilterRegistration reg;
+
+    /**
+     * Create new wrapper
+     * @param c Wrapped registration
+     */
+    public FilterRegistrationWrapper(@NotNull final FilterRegistration c) {
+        this.reg = c;
+    }
+
+    private EnumSet<DispatcherType> wrap(final EnumSet<javax.servlet.DispatcherType> dispatcherTypes) {
+        final EnumSet<DispatcherType> set = EnumSet.noneOf(DispatcherType.class);
+        if ( dispatcherTypes.contains(javax.servlet.DispatcherType.ASYNC)) {
+            set.add(DispatcherType.ASYNC);
+        }
+        if ( dispatcherTypes.contains(javax.servlet.DispatcherType.ERROR)) {
+            set.add(DispatcherType.ERROR);
+        }
+        if ( dispatcherTypes.contains(javax.servlet.DispatcherType.FORWARD)) {
+            set.add(DispatcherType.FORWARD);
+        }
+        if ( dispatcherTypes.contains(javax.servlet.DispatcherType.INCLUDE)) {
+            set.add(DispatcherType.INCLUDE);
+        }
+        if ( dispatcherTypes.contains(javax.servlet.DispatcherType.REQUEST)) {
+            set.add(DispatcherType.REQUEST);
+        }
+        return set;
+    }
+
+    @Override
+    public void addMappingForServletNames(final EnumSet<javax.servlet.DispatcherType> dispatcherTypes, final boolean isMatchAfter,
+            final String... servletNames) {
+        reg.addMappingForServletNames(wrap(dispatcherTypes), isMatchAfter, servletNames);
+    }
+
+    @Override
+    public String getName() {
+        return reg.getName();
+    }
+
+    @Override
+    public String getClassName() {
+        return reg.getClassName();
+    }
+
+    @Override
+    public boolean setInitParameter(final String name, final String value) {
+        return reg.setInitParameter(name, value);
+    }
+
+    @Override
+    public Collection<String> getServletNameMappings() {
+        return reg.getServletNameMappings();
+    }
+
+    @Override
+    public void addMappingForUrlPatterns(final EnumSet<javax.servlet.DispatcherType> dispatcherTypes, final boolean isMatchAfter,
+            final String... urlPatterns) {
+        reg.addMappingForUrlPatterns(wrap(dispatcherTypes), isMatchAfter, urlPatterns);
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        return reg.getInitParameter(name);
+    }
+
+    @Override
+    public Set<String> setInitParameters(final Map<String, String> initParameters) {
+        return reg.setInitParameters(initParameters);
+    }
+
+    @Override
+    public Collection<String> getUrlPatternMappings() {
+        return reg.getUrlPatternMappings();
+    }
+
+    @Override
+    public Map<String, String> getInitParameters() {
+        return reg.getInitParameters();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletMappingWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletMappingWrapper.java
new file mode 100644
index 0000000..d8a8679
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletMappingWrapper.java
@@ -0,0 +1,72 @@
+/*
+ * 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.javaxwrappers;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.HttpServletMapping;
+
+/**
+ * Http Mapping wrapper
+ */
+public class HttpServletMappingWrapper implements javax.servlet.http.HttpServletMapping {
+
+    private final HttpServletMapping mapping;
+
+    /**
+     * Create new wrapper
+     * @param c Wrapped mapper
+     */
+    public HttpServletMappingWrapper(@NotNull final HttpServletMapping c) {
+        this.mapping = c;
+    }
+
+    @Override
+    public String getMatchValue() {
+        return mapping.getMatchValue();
+    }
+
+    @Override
+    public String getPattern() {
+        return mapping.getPattern();
+    }
+
+    @Override
+    public String getServletName() {
+        return mapping.getServletName();
+    }
+
+    @Override
+    public javax.servlet.http.MappingMatch getMappingMatch() {
+        switch (mapping.getMappingMatch()) {
+        case CONTEXT_ROOT : return javax.servlet.http.MappingMatch.CONTEXT_ROOT;
+        case DEFAULT : return javax.servlet.http.MappingMatch.DEFAULT;
+        case EXACT : return javax.servlet.http.MappingMatch.EXACT;
+        case EXTENSION : return javax.servlet.http.MappingMatch.EXTENSION;
+        case PATH : return javax.servlet.http.MappingMatch.PATH;
+        }
+        return null;
+    }
+
+    /**
+     * Get the wrapped mapping
+     * @return The mapping
+     */
+    public HttpServletMapping getMapping() {
+        return this.mapping;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletRequestWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletRequestWrapper.java
new file mode 100644
index 0000000..801f323
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletRequestWrapper.java
@@ -0,0 +1,264 @@
+/*
+ * 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.javaxwrappers;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.Part;
+import jakarta.servlet.http.PushBuilder;
+
+/**
+ * Http servlet request wrapper
+ */
+public class HttpServletRequestWrapper extends ServletRequestWrapper
+    implements javax.servlet.http.HttpServletRequest {
+
+    private final HttpServletRequest request;
+
+    /**
+     * Create new request
+     * @param r wrapped request
+     */
+    public HttpServletRequestWrapper(@NotNull final HttpServletRequest r) {
+        super(r);
+        this.request = r;
+    }
+
+    @Override
+    public String getAuthType() {
+        return this.request.getAuthType();
+    }
+
+    @Override
+    public javax.servlet.http.Cookie[] getCookies() {
+        return CookieWrapper.wrap(this.request.getCookies());
+    }
+
+    @Override
+    public long getDateHeader(final String name) {
+        return this.request.getDateHeader(name);
+    }
+
+    @Override
+    public String getHeader(final String name) {
+        return this.request.getHeader(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaders(final String name) {
+        return this.request.getHeaders(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaderNames() {
+        return this.request.getHeaderNames();
+    }
+
+    @Override
+    public int getIntHeader(final String name) {
+        return this.request.getIntHeader(name);
+    }
+
+    @Override
+    public String getMethod() {
+        return this.request.getMethod();
+    }
+
+    @Override
+    public String getPathInfo() {
+        return this.request.getPathInfo();
+    }
+
+    @Override
+    public String getPathTranslated() {
+        return this.request.getPathTranslated();
+    }
+
+    @Override
+    public String getContextPath() {
+        return this.request.getContextPath();
+    }
+
+    @Override
+    public String getQueryString() {
+        return this.request.getQueryString();
+    }
+
+    @Override
+    public String getRemoteUser() {
+        return this.request.getRemoteUser();
+    }
+
+    @Override
+    public boolean isUserInRole(final String role) {
+        return this.request.isUserInRole(role);
+    }
+
+    @Override
+    public Principal getUserPrincipal() {
+        return this.request.getUserPrincipal();
+    }
+
+    @Override
+    public String getRequestedSessionId() {
+        return this.request.getRequestedSessionId();
+    }
+
+    @Override
+    public String getRequestURI() {
+        return this.request.getRequestURI();
+    }
+
+    @Override
+    public StringBuffer getRequestURL() {
+        return this.request.getRequestURL();
+    }
+
+    @Override
+    public String getServletPath() {
+        return this.request.getServletPath();
+    }
+
+    @Override
+    public javax.servlet.http.HttpSession getSession(final boolean create) {
+        final HttpSession session = this.request.getSession(create);
+        if ( session != null ) {
+            return new HttpSessionWrapper(session);
+        }
+        return null;
+    }
+
+    @Override
+    public javax.servlet.http.HttpSession getSession() {
+        return new HttpSessionWrapper(this.request.getSession());
+    }
+
+    @Override
+    public String changeSessionId() {
+        return this.request.changeSessionId();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        return this.request.isRequestedSessionIdValid();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromCookie() {
+        return this.request.isRequestedSessionIdFromCookie();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromURL() {
+        return this.request.isRequestedSessionIdFromURL();
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public boolean isRequestedSessionIdFromUrl() {
+        return this.request.isRequestedSessionIdFromUrl();
+    }
+
+    @Override
+    public boolean authenticate(final javax.servlet.http.HttpServletResponse response) throws IOException, javax.servlet.ServletException {
+        try {
+            return this.request.authenticate((HttpServletResponse)org.apache.felix.http.base.internal.jakartawrappers.ServletResponseWrapper.getWrapper(response));
+        } catch ( final jakarta.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void login(final String username, final String password) throws javax.servlet.ServletException {
+        try {
+            this.request.login(username, password);
+        } catch ( final jakarta.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public void logout() throws javax.servlet.ServletException {
+        try {
+            this.request.logout();
+        } catch ( final jakarta.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public Collection<javax.servlet.http.Part> getParts() throws IOException, javax.servlet.ServletException {
+        try {
+            final List<javax.servlet.http.Part> result = new ArrayList<>();
+            for(final Part p : this.request.getParts()) {
+                result.add(new PartWrapper(p));
+            }
+            return result;
+        } catch ( final jakarta.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public javax.servlet.http.Part getPart(final String name) throws IOException, javax.servlet.ServletException {
+        try {
+            return new PartWrapper(this.request.getPart(name));
+        } catch ( final jakarta.servlet.ServletException e ) {
+            throw ServletExceptionUtil.getServletException(e);
+        }
+    }
+
+    @Override
+    public <T extends javax.servlet.http.HttpUpgradeHandler> T upgrade(final Class<T> handlerClass) throws IOException, javax.servlet.ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public javax.servlet.http.HttpServletMapping getHttpServletMapping() {
+        return new HttpServletMappingWrapper(this.request.getHttpServletMapping());
+    }
+
+    @Override
+    public javax.servlet.http.PushBuilder newPushBuilder() {
+        final PushBuilder builder = this.request.newPushBuilder();
+        if ( builder != null ) {
+            return new PushBuilderWrapper(builder);
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getTrailerFields() {
+        return this.request.getTrailerFields();
+    }
+
+    @Override
+    public boolean isTrailerFieldsReady() {
+        return this.request.isTrailerFieldsReady();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletResponseWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletResponseWrapper.java
new file mode 100644
index 0000000..a22738c
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpServletResponseWrapper.java
@@ -0,0 +1,151 @@
+/*
+ * 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.javaxwrappers;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.felix.http.base.internal.jakartawrappers.CookieWrapper;
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * Http servlet response wrapper
+*/
+public class HttpServletResponseWrapper extends ServletResponseWrapper
+    implements javax.servlet.http.HttpServletResponse {
+
+    private final HttpServletResponse response;
+
+    /**
+     * Create a new response
+     * @param r Wrapped response
+     */
+    public HttpServletResponseWrapper(@NotNull final HttpServletResponse r) {
+        super(r);
+        this.response = r;
+    }
+
+    @Override
+    public void addCookie(final javax.servlet.http.Cookie cookie) {
+        this.response.addCookie(new CookieWrapper(cookie));
+    }
+
+    @Override
+    public boolean containsHeader(final String name) {
+        return this.response.containsHeader(name);
+    }
+
+    @Override
+    public String encodeURL(final String url) {
+        return this.response.encodeURL(url);
+    }
+
+    @Override
+    public String encodeRedirectURL(final String url) {
+        return this.response.encodeRedirectURL(url);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public String encodeUrl(final String url) {
+        return this.response.encodeUrl(url);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public String encodeRedirectUrl(final String url) {
+        return this.response.encodeRedirectUrl(url);
+    }
+
+    @Override
+    public void sendError(final int sc, final String msg) throws IOException {
+        this.response.sendError(sc, msg);
+    }
+
+    @Override
+    public void sendError(final int sc) throws IOException {
+        this.response.sendError(sc);
+    }
+
+    @Override
+    public void sendRedirect(final String location) throws IOException {
+        this.response.sendRedirect(location);
+    }
+
+    @Override
+    public void setDateHeader(final String name, final long date) {
+        this.response.setDateHeader(name, date);
+    }
+
+    @Override
+    public void addDateHeader(final String name, final long date) {
+        this.response.addDateHeader(name, date);
+    }
+
+    @Override
+    public void setHeader(final String name, final String value) {
+        this.response.setHeader(name, value);
+    }
+
+    @Override
+    public void addHeader(final String name, final String value) {
+        this.response.addHeader(name, value);
+    }
+
+    @Override
+    public void setIntHeader(final String name, final int value) {
+        this.response.setIntHeader(name, value);
+    }
+
+    @Override
+    public void addIntHeader(final String name, final int value) {
+        this.response.addIntHeader(name, value);
+    }
+
+    @Override
+    public void setStatus(int sc) {
+        this.response.setStatus(sc);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void setStatus(final int sc, final String sm) {
+        this.response.setStatus(sc, sm);
+    }
+
+    @Override
+    public int getStatus() {
+        return this.response.getStatus();
+    }
+
+    @Override
+    public String getHeader(final String name) {
+        return this.response.getHeader(name);
+    }
+
+    @Override
+    public Collection<String> getHeaders(final String name) {
+        return this.response.getHeaders(name);
+    }
+
+    @Override
+    public Collection<String> getHeaderNames() {
+        return this.response.getHeaderNames();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpSessionContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpSessionContextWrapper.java
new file mode 100644
index 0000000..b54a369
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpSessionContextWrapper.java
@@ -0,0 +1,55 @@
+/*
+ * 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.javaxwrappers;
+
+import java.util.Enumeration;
+
+import org.jetbrains.annotations.NotNull;
+
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSessionContext;
+
+/**
+ * http session context wrapper
+ */
+@SuppressWarnings("deprecation")
+public class HttpSessionContextWrapper implements javax.servlet.http.HttpSessionContext {
+
+    private final HttpSessionContext context;
+
+    /**
+     * Create new context
+     * @param c Wrapped context
+     */
+    public HttpSessionContextWrapper(@NotNull final HttpSessionContext c) {
+        this.context = c;
+    }
+
+    @Override
+    public javax.servlet.http.HttpSession getSession(final String sessionId) {
+        final HttpSession session = context.getSession(sessionId);
+        if ( session != null ) {
+            return new HttpSessionWrapper(session);
+        }
+        return null;
+    }
+
+    @Override
+    public Enumeration<String> getIds() {
+        return context.getIds();
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpSessionWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpSessionWrapper.java
new file mode 100644
index 0000000..06412d3
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/javaxwrappers/HttpSessionWrapper.java
@@ -0,0 +1,130 @@
+/*
+ * 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.javaxwrappers;
+
+import java.util.Enumeration;
+
+import org.jetbrains.annotations.NotNull;
... 12668 lines suppressed ...