On Dec 14, 2011, at 9:26 AM, Daniel Kulp wrote:
> On Tuesday, December 13, 2011 12:20:21 PM Rahul Somasunderam wrote:
>> Hi,
>>
>> I'm working on a health project. There are a bunch of standards that we use
>> that are available to us as a WSDL. The WSDLs are located at
>> ftp://ftp.ihe.net/TF_Implementation_Material/ITI/wsdl/
>>
>> However different implementors serve the WSDL with different namespaces in
>> the WSDL. And this seems to make it hard for me to integrate with any
>> random implementor.
>>
>> For instance, this is my own server using CXF -
>> http://107.20.211.185/hd/services/xdsregistryb?wsdl This is NIST
>> implementing the same using Axis2 -
>> http://ihexds.nist.gov:9080/tf6/services/xdsregistryb
>>
>> I've created a testcase that shows how my CXF client code fails.
>>
>> How am I to deal with changing namespaces in WSDLs?
>
> Well, that Axis2 wsdl is COMPLETELY bogus compared to the specifications that
> you list in the first link. It's not just the namespaces. (the namespaces
> ARE part of the spec and thus the services that implement the standard/spec
> should be respecting that) However, the structure of the messages are also
> completely different. Look at the request for the AdhocQuery operation.
>
> For the spec and for the CXF service, a SOAP:Body would have a child element
> of:
> {urn:oasis:names:tc:ebxml-regrep:xsd:query:3.0}AdhocQueryRequest
>
> For the Axis2 service, the soap body would actually be empty. No content
> what
> so ever. The message in the wsdl looks like:
> <wsdl:message name="AdhocQueryRequestRequest"/>
>
> Basically, the CXF service properly looks like the standard, the other one
> does not at all resemble it.
>
That's true, but I don't control what technology is used by another
implementor. I still need to be able to talk to their implementation using my
client code.
Is there some simpler way of doing this in CXF?
I tinkered with CXF default behavior at each step of the process:
1. During service creation I need to parse the WSDL and provide the service
QName. This means there's a second call by CXF to the WSDL.
2. To create the port, I need to specify the port QName again. Unfortunately,
there are multiple ports available in the Axis2 WSDL and I need to identify the
one with SOAP 1.2.
3. Then the method call is again a problem, because method names are not
identical, and I don't know how to get around it. Is it possible to have CXF
use the action names instead of method names?
private def doTest(String endpoint, String patientId) {
// Constants
def soap12 = new Namespace("http://schemas.xmlsoap.org/wsdl/soap12/")
def wsdl = new Namespace("http://schemas.xmlsoap.org/wsdl/")
// Derivations
def endpointUrl = endpoint.toURL()
def webServiceDef = new XmlParser().parseText(endpointUrl.text)
def targetNamespace = webServiceDef.@targetNamespace
def serviceName = webServiceDef[wsdl.service][email protected]()
println "Target Namespace: ${targetNamespace}"
println "Service Name: ${serviceName}"
def soap12Binding = webServiceDef[wsdl.binding].find { binding ->
binding[soap12.binding]
}
println "Binding name: ${soap12Binding?.@name}"
def soap12Port = webServiceDef[wsdl.service][wsdl.port].find { port ->
[email protected](soap12Binding.@name)
}
println "Port name: ${soap12Port?.@name}"
def service = new DocumentRegistryService(endpointUrl, new
QName(targetNamespace, serviceName))
def port = service.getPort(new QName(targetNamespace, soap12Port.@name),
DocumentRegistryPortType)
def resp = port.documentRegistryRegistryStoredQuery(new AdhocQueryRequest(
responseOption: new ResponseOptionType(returnType: 'LeafClass',
returnComposedObjects: true),
adhocQuery: new AdhocQueryType(
id: "urn:uuid:14d4debf-8f97-4251-9a74-a90016b0af0d",
slot: [
new SlotType1(
name: '$XDSDocumentEntryPatientId',
valueList: new ValueListType(value: [patientId]),
),
new SlotType1(name: '\$XDSDocumentEntryStatus',
valueList: new ValueListType(value:
['urn:oasis:names:tc:ebxml-regrep:StatusType:Approved'])
)
]
)
))
}
I get this exception when testing against the Axis2 site:
java.lang.Error: Undefined operation name DocumentRegistry_RegistryStoredQuery
at
com.sun.xml.internal.ws.model.JavaMethodImpl.freeze(JavaMethodImpl.java:316)
at
com.sun.xml.internal.ws.model.AbstractSEIModelImpl.freeze(AbstractSEIModelImpl.java:93)
at
com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:250)
at
com.sun.xml.internal.ws.client.WSServiceDelegate.createSEIPortInfo(WSServiceDelegate.java:687)
at
com.sun.xml.internal.ws.client.WSServiceDelegate.addSEI(WSServiceDelegate.java:675)
at
com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:330)
at
com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:313)
at
com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:295)
at javax.xml.ws.Service.getPort(Service.java:92)
at javax.xml.ws.Service$getPort.call(Unknown Source)
at ihe.iti.xds_b._2007.NamespaceTest.doTest(NamespaceTest.groovy:51)
at
ihe.iti.xds_b._2007.NamespaceTest.testAgainstNist(NamespaceTest.groovy:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at
com.intellij.junit3.JUnit3IdeaTestRunner.doRun(JUnit3IdeaTestRunner.java:139)
at
com.intellij.junit3.JUnit3IdeaTestRunner.startRunnerWithArgs(JUnit3IdeaTestRunner.java:52)
at
com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:199)
at
com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Which makes sense because the operation names are different. However the action
names are the same. Is there some way I can tinker with it to get the right
operation name to be called?
R,
rahul
> --
> Daniel Kulp
> [email protected] - http://dankulp.com/blog
> Talend Community Coder - http://coders.talend.com