通过 API 创建新的 CXF 总线

Create new CXF Bus via API

我正在尝试将 Apache CXF 与 OSGI enRoute 结合使用。不同之处在于我不想使用 cfg.xml 文件,而是通过 API 启动我的服务端点。下面就是这样一个例子:

    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();

我遇到的问题是为每个 OSGI 包创建一个不同的 CXF 总线,因此允许我在每次对应的包是 activated/deactivated 时 create/destroy 总线。复制以下 Karaf 命令也是一个目标:

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

问题是我没有看到 API 用于创建和销毁 CXF 总线。上面列出的 Karaf 代码似乎不适用于 enRoute。

我想可以在包中创建一个 cfg.xml 文件来创建总线,但是我没有看到 APIs 用于获取具有给定别名的总线。呃

下面的 link 看起来很有前途,但是当适应 CXFNonSpringServlet 的子类时......我没有得到相应的 CXF 总线,我似乎也无法通过 API 创建一个:

registering servlet in OSGi that receives parameters

所以我的问题是...有没有人通过 API 在 OSGI 中成功获取、创建和销毁 CXF 总线(和相应的 servlet)?

谢谢, 兰迪

您可以实现一个 Bundle-Activator,registers/unregisters 捆绑包 start/stop 上的 CXF 总线。

要创建总线,您可以使用 BusFactory class。创建的总线必须注册为服务。已注册的服务保存在一个列表中,以便能够在捆绑停止时注销它们。

以下(可能不太漂亮)示例应该能给您一个思路:

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();
      }
   }
} 

对于 JAX-RS 服务,您现在可以这样继续:

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

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

  Server server = serviceFactory.create();

有关详细信息,请参阅 http://cxf.apache.org/docs/jaxrs-services-configuration.html

CXFNonSpringServlet 源代码显示此 servlet 子class 根据需要创建 CXF 总线。因此,我采用的方法是简单地创建 CXFNonSpringServlet class 的实例,并使用所需的别名将其注册到 HTTPService。

问题是无法在 BundleActivator class 中调用以下代码,因为无法保证注册 servlet 所需的 HTTPService 在激活包时存在。为此,我创建了一个带有 HTTPService 引用的组件,并在组件激活期间注册了 servlet。我进一步使该组件成为 'immediate component' 以确保在启动期间进行服务注册。

@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);
    }

欢迎提出有关将此代码移至 Bundle Activator class 的建议,但请注意,有必要确保调用 Bundle Activator 时 HTTPService 可用。