CXF/Spring Injecting Top-Level Service Name and Namespace into JAX-WS Interface

Go To StackoverFlow.com

1

I'm flying a CXF-based Web service not unsimilar to the example on the CXF Web site at http://cxf.apache.org/docs/jax-ws-configuration.html . This service has an implemented endpoint based on the following sample context:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://cxf.apache.org/jaxws 
        http://cxf.apache.org/schemas/jaxws.xsd">

    <jaxws:endpoint id="myServiceMembersImpl"
        implementor="#myService"
        endpointName="e:MyServiceMembersEndpoint"
        serviceName="s:MyServiceMembersService"
        address="http://localhost:8080/myservicemembers"
        xmlns:e="http://localhost:8080/myservicemembers/ns"
        xmlns:s="http://localhost:8080/myservicemembers/ns"/>

</beans>

Then, of course, there is the Java ...

Interface:

package com.me.service;

@WebService
public interface MyService {

String MEMBER = "MEMBER";

@WebResult(name = MEMBER)
Member getMember(@WebParam(name = "memberId") long memberId) throws Exception;
     // ... 
     // more interface declarations 
     // ... 

} // end interface 

and, implementation:

package com.me.service.impl;

@WebService(endpointInterface = "com.me.service.MyService")
@Path("/")
public class MyServiceMembersImpl implements MyService {

@GET
@Path("/{id}")
@Consumes({ APP_JSON, APP_XML })
@Produces({ APP_JSON, APP_XML })
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public Member getMember(@PathParam("id") final long memberId) throws Exception {

        // ... 
        // business logic 
        // ... 
        return theMember; 

     } // end method 

} // end class 

Which returns a WSDL that starts somewhat like this:

<?xml version="1.0" encoding="UTF-8" ?> 
<wsdl:definitions name="MyServiceImplService" 
    targetNamespace="http://localhost:8080/myservicemembers/ns" 
    xmlns:ns1="**http://service.me.com/**" 
    xmlns:ns2="http://schemas.xmlsoap.org/soap/http" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:tns="http://localhost:8080/myservicemembers/ns" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <wsdl:import location="http://localhost:8080/myservicemembers?wsdl=**MyService**.wsdl" 
        namespace="**http://service.me.com/**" /> 
        <wsdl:binding name="MyServiceImplServiceSoapBinding" type="ns1:**MyService**">
<!-- ... --> 
</wsdl:definitions> 

It's fairly simple using the "jaxws:endpoint" element in the application context to change the settings for the endpoint. This fleshes out the service name, endpoint name and other fields. However, the top-level interface still has a say in the WSDL file. The STARRED items above are from the top-level interface. How can I inject values into the top-level interface for the targetNamespace and serviceName?

My good reasons for doing this include (1) not wanting to expose package names in the WSDL and (2) wanting to switch namespaces as an application moves down a deployment runway. Thus I cannot use annotations since those are compile-time values, I can't substitute them with property placeholders, and I will not recompile my code in the production tier.

2012-04-03 21:04
by ingyhere
I'm open to any solutions, including static blocks and direct accessors, as long as they can be set with property substitutions - ingyhere 2012-04-03 21:10


1

You can do this by programmatically creating the services using JaxWsServerFactoryBean instead of using <jaxws:endpoint> in your Spring config. Doing the creation programmatically gives you a lot more control.

For example:

@Autowired
var myServiceImpl: MyService = _

val propMap = mutable.HashMap[String, AnyRef]("org.apache.cxf.logging.FaultListener"->faultListener.asInstanceOf[AnyRef])

val sf = new JaxWsServerFactoryBean
sf.setServiceBean(myServiceImpl)
sf.setAddress("/myservice")
sf.setServiceName(new QName(WEB_SERVICE_NAMESPACE, "myService", "MyService"))
sf.setProperties(propMap)
sf.create
2012-04-04 02:44
by sourcedelica
Thanks very much for this information. I am looking at this. I wanted to post this link, which I think completes the picture of a CXF non-Spring implementation: http://www.axlrosen.net/stuff/cxf-without-spring.html - ingyhere 2012-04-04 06:06