通过 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 命令也是一个目标:
问题是我没有看到 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 可用。
我正在尝试将 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 命令也是一个目标:
问题是我没有看到 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 可用。