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.
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