Randy Leonard
Randy Leonard

Reputation: 683

Create new CXF Bus via API

I am attempting to use Apache CXF with OSGI enRoute. The twist is that I'd prefer not to use the cfg.xml files and instead spin up my service endpoints via API. The following is such an example:

    InvolvedPartySoap12EndpointImpl involvedPartyServiceImpl = new InvolvedPartySoap12EndpointImpl();
    ServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
    svrFactory.setServiceClass(InvolvedPartyPortType.class);
    svrFactory.setAddress("/bin/InvolvedParty");
    svrFactory.setBus(bus);
    svrFactory.setServiceBean(involvedPartyServiceImpl);
    _server = svrFactory.create();

The issue I am having is creating a distinct CXF bus for each OSGI bundle, thus allowing me to create/destroy the bus each time the corresponding bundle is activated/deactivated. Replicating the following Karaf commands would also be a goal:

https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.2/html/API_Reference/files/cxf/org/apache/cxf/karaf/commands/CXFController.html

The problem is that I just don't see APIs for creating and destroying a CXF Bus. And the Karaf code listed above does not seem to work for enRoute.

I suppose it would be possible to create a cfg.xml file within the bundle to create the bus, but then I don't see APIs for fetching a bus with a given alias. Ugh.

The following link seemed promising, but when adapting to a subclass of CXFNonSpringServlet... I don't get a corresponding CXF Bus, nor can I seem to create one via API:

registering servlet in OSGi that receives parameters

So my question is... has anyone been successful at fetching, creating, and destroying CXF busses (and corresponding servlets) via API within OSGI?

Thanks, Randy

Upvotes: 1

Views: 960

Answers (2)

Randy Leonard
Randy Leonard

Reputation: 683

The CXFNonSpringServlet source code shows this servlet subclass creates a CXF Bus upon demand. So the approach I've taken is to simply create an instance of the CXFNonSpringServlet class and register it with the HTTPService with the desired alias.

The catch is the following code cannot be invoked within the BundleActivator class, as there can be no guarantee the HTTPService required to register the servlet will exist at the time of bundle activation. To this end, I've created a component with an HTTPService reference and register the servlet during component activation. I've further made the component an 'immediate component' to ensure service registration takes place during startup.

@Component(immediate = true)
public class SoapBootstrap
{
    private static final long serialVersionUID = 1L;
    private static final String Alias = "/party";

    private HttpService _httpService;
    private CXFNonSpringServlet _servlet;

    @Reference
    public void setHttpService(HttpService theHttpService)
    {
        try {
            _httpService = theHttpService;
            _servlet = new CXFNonSpringServlet();
            _httpService.registerServlet(Alias, _servlet, null, null);
            registerEndpoints();
        } catch (NamespaceException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }

    private void registerEndpoints()
    {
        try {
            XyzSoap12EndpointImpl xyzServiceImpl = new XyzSoap12EndpointImpl();
            ServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
            svrFactory.setServiceClass(XyzPortType.class);
            svrFactory.setAddress("/xyz");
            svrFactory.setBus(_servlet.getBus());
            svrFactory.setServiceBean(xyzServiceImpl);
            svrFactory.create();
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
        }
    }


    @Activate
    void activate(BundleContext context)
    {
    }


    @Deactivate
    void deactivate(BundleContext context)
    {
        _httpService.unregister(Alias);
    }

Suggestions on moving this code to the Bundle Activator class is welcome, but note it is necessary to ensure the HTTPService is available when the Bundle Activator is invoked.

Upvotes: 1

Oliver Wespi
Oliver Wespi

Reputation: 55

You could implement a Bundle-Activator that registers/unregisters a CXF bus on bundle start/stop.

To create a bus you can use the BusFactory class. The created Bus has to be registered as a service. The registered services are kept in a List to be able to unregister them on bundle stop.

Following (perhaps not too beautyful) example should give you an idea:

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
...


public class MyBundleActivator implements BundleActivator {

   private final List<ServiceRegistration> serviceReferences = new ArrayList<>();

   private Bus cxfBus;
   private BundleContext bundleContext;

   @Override
   public void start(BundleContext bundleContext) throws Exception {
      this.bundleContext = bundleContext;
      createAndRegisterCxfBus();
   }

   private void createAndRegisterCxfBus() {
      cxfBus = BusFactory.newInstance().createBus();
      cxfBus.setExtension(MyBundleActivator.class.getClassLoader(), ClassLoader.class);
      registerService(Bus.class.getName(), cxfBus);
   }

   private void registerService(String serviceTypeName, Object service) {
      Dictionary properties = new Properties();
      ServiceRegistration serviceReference = bundleContext.registerService(serviceTypeName, service, properties);
      serviceReferences.add(serviceReference);
   }

   @Override
   public void stop(BundleContext bundleContext) throws Exception {
      unregisterServices();
   }

   private void unregisterServices() {
      for (ServiceRegistration serviceReference : serviceReferences) {
         serviceReference.unregister();
      }
   }
} 

For a JAX-RS service you could now go on like this:

  JAXRSServerFactoryBean serviceFactory = new JAXRSServerFactoryBean();
  serviceFactory.setBus(cxfBus);

  ... configure with providers etc using factory API ....

  Server server = serviceFactory.create();

See http://cxf.apache.org/docs/jaxrs-services-configuration.html for further information.

Upvotes: 0

Related Questions