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

jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karaf.git


The following commit(s) were added to refs/heads/main by this push:
     new e02e22b05 fix(#656): Register CXF servlet via OSGi Servlet Whiteboard 
to restore service listing page (#687)
e02e22b05 is described below

commit e02e22b05190a92f61020344ce7bc6eb28de0fa1
Author: JB Onofré <[email protected]>
AuthorDate: Thu Mar 12 15:50:02 2026 +0100

    fix(#656): Register CXF servlet via OSGi Servlet Whiteboard to restore 
service listing page (#687)
    
    The CXF "Available SOAP Services" listing page was unavailable because
    HttpService was removed in OSGi 8. Replace the defunct HttpService-based
    servlet registration with the OSGi Servlet Whiteboard pattern, which
    registers the CXFNonSpringServlet as an OSGi service with whiteboard
    properties picked up by pax-web. Add http-whiteboard feature dependency
    to camel-cxf.
---
 .../http/osgi/HTTPTransportActivator.java          |  29 +++---
 .../http/osgi/HttpServiceTrackerCust.java          |  70 -------------
 .../cxf/transport/http/osgi/ServletExporter.java   | 109 +++++++++------------
 features/src/main/feature/camel-features.xml       |   1 +
 4 files changed, 68 insertions(+), 141 deletions(-)

diff --git 
a/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HTTPTransportActivator.java
 
b/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HTTPTransportActivator.java
index 1586c3913..663ef466f 100644
--- 
a/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HTTPTransportActivator.java
+++ 
b/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HTTPTransportActivator.java
@@ -17,23 +17,27 @@
 
 package org.apache.camel.component.cxf.transport.http.osgi;
 
+import jakarta.servlet.Servlet;
 import org.apache.cxf.common.util.CollectionUtils;
 import org.apache.cxf.common.util.PropertyUtils;
 import org.apache.cxf.transport.http.DestinationRegistry;
 import org.apache.cxf.transport.http.DestinationRegistryImpl;
 import org.apache.cxf.transport.http.HTTPConduitConfigurer;
 import org.apache.cxf.transport.http.HTTPTransportFactory;
+import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
 import org.osgi.service.cm.ManagedServiceFactory;
-import org.osgi.service.http.HttpService;
-import org.osgi.util.tracker.ServiceTracker;
 
 public class HTTPTransportActivator implements BundleActivator {
+    private static final String CXF_CONFIG_PID = "org.apache.cxf.osgi";
     private static final String DISABLE_DEFAULT_HTTP_TRANSPORT = 
"org.apache.cxf.osgi.http.transport.disable";
-    private ServiceTracker<HttpService, ?> httpServiceTracker;
+
+    private ServiceRegistration<ManagedService> servletPublisherReg;
+    private ServletExporter servletExporter;
 
     @Override
     public void start(final BundleContext context) throws Exception {
@@ -46,18 +50,18 @@ public class HTTPTransportActivator implements 
BundleActivator {
                 "org.apache.cxf.http.conduit-configurer");
 
         if 
(PropertyUtils.isTrue(context.getProperty(DISABLE_DEFAULT_HTTP_TRANSPORT))) {
-            //TODO: Review if it also makes sense to support 
"http.transport.disable"
-            //      directly in the CXF_CONFIG_SCOPE properties file
             return;
         }
 
         DestinationRegistry destinationRegistry = new 
DestinationRegistryImpl();
         HTTPTransportFactory transportFactory = new 
HTTPTransportFactory(destinationRegistry);
 
-        // HttpService is no longer available in OSGI 8
-//        HttpServiceTrackerCust customizer = new 
HttpServiceTrackerCust(destinationRegistry, context);
-//        httpServiceTracker = new ServiceTracker<>(context, 
HttpService.class, customizer);
-//        httpServiceTracker.open();
+        // Register the CXF servlet using OSGi Servlet Whiteboard
+        Servlet servlet = new CXFNonSpringServlet(destinationRegistry, false);
+        servletExporter = new ServletExporter(servlet, context);
+        servletPublisherReg = context.registerService(ManagedService.class,
+                servletExporter,
+                CollectionUtils.singletonDictionary(Constants.SERVICE_PID, 
CXF_CONFIG_PID));
 
         context.registerService(DestinationRegistry.class.getName(), 
destinationRegistry, null);
         context.registerService(HTTPTransportFactory.class.getName(), 
transportFactory, null);
@@ -71,8 +75,11 @@ public class HTTPTransportActivator implements 
BundleActivator {
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        if (httpServiceTracker != null) {
-            httpServiceTracker.close();
+        if (servletPublisherReg != null) {
+            servletPublisherReg.unregister();
+        }
+        if (servletExporter != null) {
+            servletExporter.destroy();
         }
     }
 }
diff --git 
a/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HttpServiceTrackerCust.java
 
b/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HttpServiceTrackerCust.java
deleted file mode 100644
index 125526a56..000000000
--- 
a/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/HttpServiceTrackerCust.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.camel.component.cxf.transport.http.osgi;
-
-import jakarta.servlet.Servlet;
-import org.apache.cxf.common.util.CollectionUtils;
-import org.apache.cxf.transport.http.DestinationRegistry;
-import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-import org.osgi.service.http.HttpService;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-
-final class HttpServiceTrackerCust implements 
ServiceTrackerCustomizer<HttpService, HttpService> {
-    private static final String CXF_CONFIG_PID = "org.apache.cxf.osgi";
-    private final DestinationRegistry destinationRegistry;
-    private final BundleContext context;
-    private ServiceRegistration<ManagedService> servletPublisherReg;
-    private ServletExporter servletExporter;
-
-    HttpServiceTrackerCust(DestinationRegistry destinationRegistry, 
BundleContext context) {
-        this.destinationRegistry = destinationRegistry;
-        this.context = context;
-    }
-
-    @Override
-    public void removedService(ServiceReference<HttpService> reference, 
HttpService service) {
-        servletPublisherReg.unregister();
-        try {
-            servletExporter.updated(null);
-        } catch (ConfigurationException e) {
-            // Ignore
-        }
-    }
-
-    @Override
-    public void modifiedService(ServiceReference<HttpService> reference, 
HttpService service) {
-    }
-
-    @Override
-    public HttpService addingService(ServiceReference<HttpService> reference) {
-        HttpService httpService = context.getService(reference);
-        Servlet servlet = new CXFNonSpringServlet(destinationRegistry, false);
-        servletExporter = new ServletExporter(servlet, httpService);
-        servletPublisherReg = context.registerService(ManagedService.class,
-                servletExporter,
-                CollectionUtils.singletonDictionary(Constants.SERVICE_PID,
-                        CXF_CONFIG_PID));
-        return httpService;
-    }
-}
diff --git 
a/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/ServletExporter.java
 
b/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/ServletExporter.java
index 4f854d4b6..dd4cbbb12 100644
--- 
a/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/ServletExporter.java
+++ 
b/components/camel-cxf/camel-cxf-all/src/main/java/org/apache/camel/component/cxf/transport/http/osgi/ServletExporter.java
@@ -18,116 +18,105 @@
 package org.apache.camel.component.cxf.transport.http.osgi;
 
 import java.util.Dictionary;
-import java.util.Enumeration;
+import java.util.Hashtable;
 import java.util.Properties;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import jakarta.servlet.Servlet;
 import org.apache.cxf.common.logging.LogUtils;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
 
 class ServletExporter implements ManagedService {
     protected static final Logger LOG = 
LogUtils.getL7dLogger(ServletExporter.class);
     private static final String CXF_SERVLET_PREFIX = "org.apache.cxf.servlet.";
 
-    private String alias;
     private final Servlet servlet;
-    private ServiceRegistration<?> serviceRegistration;
-    private final HttpService httpService;
+    private final BundleContext bundleContext;
+    private ServiceRegistration<Servlet> servletServiceRegistration;
 
-    ServletExporter(Servlet servlet, HttpService httpService) {
+    ServletExporter(Servlet servlet, BundleContext bundleContext) {
         this.servlet = servlet;
-        this.httpService = httpService;
+        this.bundleContext = bundleContext;
     }
 
     @SuppressWarnings("rawtypes")
     @Override
     public void updated(Dictionary properties) throws ConfigurationException {
-        if (alias != null) {
+        if (servletServiceRegistration != null) {
             try {
-                LOG.log(Level.INFO, "Unregistering previous instance of \"" + 
alias + "\" servlet");
-                httpService.unregister(alias);
-            } catch (IllegalArgumentException e) {
-                // NOTE: pax-web specific...
-                if (e.getMessage() != null && e.getMessage().contains("was 
never registered")) {
-                    LOG.log(Level.INFO, "CXF OSGi servlet was not 
unregistered: " + e.getMessage());
-                } else {
-                    LOG.log(Level.SEVERE, e.getMessage(), e);
-                }
+                LOG.log(Level.INFO, "Unregistering previous CXF servlet");
+                servletServiceRegistration.unregister();
+            } catch (IllegalStateException e) {
+                LOG.log(Level.FINE, "CXF OSGi servlet was already 
unregistered: " + e.getMessage());
             }
+            servletServiceRegistration = null;
             if (properties == null) {
-                // we're simply stopping. if we couldn't unregister, that 
means we had to little time to register
-                // otherwise, we'll try to register the servlet
                 return;
             }
-            alias = null;
         }
         if (properties == null) {
             properties = new Properties();
         }
-        Properties sprops = new Properties();
-        sprops.put("init-prefix",
-                getProp(properties, CXF_SERVLET_PREFIX + "init-prefix", ""));
-        sprops.put("servlet-name",
-                getProp(properties, CXF_SERVLET_PREFIX + "name", 
"cxf-osgi-transport-servlet"));
-        sprops.put("hide-service-list-page",
+
+        String context = (String) getProp(properties, CXF_SERVLET_PREFIX + 
"context", "/cxf");
+        String servletName = (String) getProp(properties, CXF_SERVLET_PREFIX + 
"name", "cxf-osgi-transport-servlet");
+
+        // Build Servlet Whiteboard service properties
+        Hashtable<String, Object> whiteboardProps = new Hashtable<>();
+        whiteboardProps.put("osgi.http.whiteboard.servlet.name", servletName);
+        whiteboardProps.put("osgi.http.whiteboard.servlet.pattern", context + 
"/*");
+        whiteboardProps.put("osgi.http.whiteboard.servlet.async-supported",
+                Boolean.valueOf(getProp(properties, CXF_SERVLET_PREFIX + 
"async-supported", "true").toString()));
+
+        // Pass CXF servlet init parameters
+        whiteboardProps.put("servlet.init.hide-service-list-page",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"hide-service-list-page", "false"));
-        sprops.put("disable-address-updates",
+        whiteboardProps.put("servlet.init.disable-address-updates",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"disable-address-updates", "true"));
-        sprops.put("base-address",
+        whiteboardProps.put("servlet.init.base-address",
                 getProp(properties, CXF_SERVLET_PREFIX + "base-address", ""));
-        sprops.put("service-list-path",
+        whiteboardProps.put("servlet.init.service-list-path",
                 getProp(properties, CXF_SERVLET_PREFIX + "service-list-path", 
""));
-        sprops.put("static-resources-list",
+        whiteboardProps.put("servlet.init.static-resources-list",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"static-resources-list", ""));
-        sprops.put("redirects-list",
+        whiteboardProps.put("servlet.init.redirects-list",
                 getProp(properties, CXF_SERVLET_PREFIX + "redirects-list", 
""));
-        sprops.put("redirect-servlet-name",
+        whiteboardProps.put("servlet.init.redirect-servlet-name",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"redirect-servlet-name", ""));
-        sprops.put("redirect-servlet-path",
+        whiteboardProps.put("servlet.init.redirect-servlet-path",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"redirect-servlet-path", ""));
-        sprops.put("service-list-all-contexts",
+        whiteboardProps.put("servlet.init.service-list-all-contexts",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"service-list-all-contexts", ""));
-        sprops.put("service-list-page-authenticate",
+        whiteboardProps.put("servlet.init.service-list-page-authenticate",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"service-list-page-authenticate", "false"));
-        sprops.put("service-list-page-authenticate-realm",
+        
whiteboardProps.put("servlet.init.service-list-page-authenticate-realm",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"service-list-page-authenticate-realm", "karaf"));
-        sprops.put("use-x-forwarded-headers",
+        whiteboardProps.put("servlet.init.use-x-forwarded-headers",
                 getProp(properties, CXF_SERVLET_PREFIX + 
"use-x-forwarded-headers", "false"));
-        sprops.put("async-supported",
-                getProp(properties, CXF_SERVLET_PREFIX + "async-supported", 
"true"));
-
-        // Accept extra properties by default, can be disabled if it is really 
needed
-        if (Boolean.valueOf(getProp(properties, CXF_SERVLET_PREFIX + 
"support.extra.properties", "true").toString())) {
-            Enumeration keys = properties.keys();
-            while (keys.hasMoreElements()) {
-                String nextKey = keys.nextElement().toString();
-                if (!nextKey.startsWith(CXF_SERVLET_PREFIX)) {
-                    sprops.put(nextKey, properties.get(nextKey));
-                }
-            }
-        }
-
 
-        if (serviceRegistration != null) {
-            serviceRegistration.unregister();
-        }
-        alias = (String)getProp(properties, CXF_SERVLET_PREFIX + "context", 
"/cxf");
-        HttpContext context = httpService.createDefaultHttpContext();
         try {
-            LOG.log(Level.INFO, "Registering new instance of \"" + alias + "\" 
servlet");
-            // TODO: use the registerServlet method when upgrading to OSGI 
CMPN 8
-//            httpService.registerServlet(alias, servlet, sprops, context);
+            LOG.log(Level.INFO, "Registering CXF servlet on " + context + " 
via Servlet Whiteboard");
+            servletServiceRegistration = 
bundleContext.registerService(Servlet.class, servlet, whiteboardProps);
         } catch (Exception e) {
             LOG.log(Level.WARNING, "Error registering CXF OSGi servlet " + 
e.getMessage(), e);
         }
     }
 
+    void destroy() {
+        if (servletServiceRegistration != null) {
+            try {
+                servletServiceRegistration.unregister();
+            } catch (IllegalStateException e) {
+                // already unregistered
+            }
+            servletServiceRegistration = null;
+        }
+    }
+
     @SuppressWarnings("rawtypes")
     private Object getProp(Dictionary properties, String key, Object 
defaultValue) {
         Object value = properties.get(key);
diff --git a/features/src/main/feature/camel-features.xml 
b/features/src/main/feature/camel-features.xml
index 27c827b0b..4e9e6e27c 100644
--- a/features/src/main/feature/camel-features.xml
+++ b/features/src/main/feature/camel-features.xml
@@ -938,6 +938,7 @@
         <feature version='${camel-osgi-version-range}'>camel-spring</feature>
         <feature 
version="${camel-osgi-jakarta-annotation2-version}">jakarta-annotation</feature>
         <feature version="[6,7)">jakarta-servlet</feature>
+        <feature>http-whiteboard</feature>
         <feature version="[3,4)">jakarta-validation</feature>
         <feature 
version="${camel-osgi-saaj-version}">jakarta-soap-implementation</feature>
         <bundle 
dependency="true">mvn:org.glassfish.hk2/osgi-resource-locator/${osgi-resource-locator-version}</bundle>

Reply via email to