Problem/Intro
I have not really used SOAP in very many years due to REST.
I have the following definition in a WSDL file:
<xs:complexType name="findByIdentifier">
<xs:sequence>
<xs:element name="arg0" type="xs:long"/>
</xs:sequence>
</xs:complexType>
The code method generated from WSDL2Java is
findByIdentifier(
#WebParam(name = "arg0", targetNamespace = "")
long arg0
)
The requirements specify that I should submit an array of long.
I see also that maxOccurs and minOccurs are missing from the WSDL.
Question
How should I modify the WSDL file I have in my project in order to have a method generated that takes an array?
If I should not hack the WSDL should I do something else like a custom implementation via an extended class or a custom client implementation (defeats the purpose of generating code)?
The solution as proposed by the team leader was to use a loop since the WSDL and the actual webservice behavior show that an array is not supported for an argument.
Related
I'm using WsdlPull library to parse the WSDL file.
Is it possible to provide relative path in the schemaLocation whiling importing external XSD inside WSDL?
e.g.
<types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://myprovider/namespace1/namespace1" schemaLocation="schema1.xsd"/>
</schema>
</types>
Schemas should be resolved relative to the containing document (in this case the WSDL's Url), so this should work. In fact we have WSDL files that do exactly what you appear to be trying to do.
However the implementation is given quite a lot of freedom during the resolution process (for example allowing it to transform the url causing it to load from a cache rather than the actual url).
As your positing this I assume this is not working?
I have defined my service on the WSDL file this way:
<wsdl:service name="guestbook">
<wsdl:port binding="tns:guestbookSOAP" name="guestbookSOAP">
<soap:address location="http://localhost:8080/soapguestbook"/>
</wsdl:port>
Still I am getting the following error message when running wsimport on it:
At least one WSDL with at least one service definition needs to be provided.
Is there anything else I need to add?
The problem in your case is that the definitions element is missing, which is like a root.
WSDL has a specific structure, for which the root element should be the DEFINITIONs, under it various other elements are present like types, messages, portType, binding, services etc.
The structure is like the below:
<definitions>
<types> data type definitions........ </types>
<message> definition of the data being communicated.... </message>
<portType> set of operations...... </portType>
<binding> protocol and data format specification.... </binding>
</definitions>
For the meaning of each WSDL element look into the link:
https://www.w3schools.com/xml/xml_wsdl.asp
I'm currently developing an application that uses webservices (SOAP 1.2). I'm interested in knowing if I can rely on the order of unbounded elements in a xmlschema sequence. Here is my definition of that sequence in the wsdl I'm using.
<xsd:complexType name="IdList">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="id" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
Does that give me any kind of guarantee on the order of the elements? Say this is an excerpt of the associated soap message:
<web:globalRecipientIds>
<!--Zero or more repetitions:-->
<web:id>1</web:id>
<web:id>15</web:id>
<web:id>7</web:id>
</web:globalRecipientIds>
Does that mean that the receiving end will treat it in the order that it appears in the SOAP message? Is this something that depends on the implementation of the receiving end? If it does, I generated the receiving end using wsdl2java from apache axis to generate the java code from the wsdl file. Can you tell me something specific about this?
The order of XML elements is significative - regardless of the schema - e.g.
<web:globalRecipientIds>
<web:id>1</web:id>
<web:id>15</web:id>
<web:id>7</web:id>
</web:globalRecipientIds>
and
<web:globalRecipientIds>
<web:id>15</web:id>
<web:id>1</web:id>
<web:id>7</web:id>
</web:globalRecipientIds>
are two different XML, and XML tools (should) preserve and recognize the order of elements.
Having said that, this does not guarantee that 'the receiving end will treat it in the order that it appears in the SOAP message' - depends on what the receiving end does with the XML. It receives an ordered list of ids, but if (for example) puts those ids in a dictionary or some other hashed structure the order is lost.
What do these parameters do and what are they used for?
<service name="...">
<parameter name="wsdlPortType" value="..."/>
</service>
Also, if anyone can explain the parameters wsdlServicePort, wsdlTargetNamespace, and wsdlServiceElement, that would be appreciated.
Axis 1.4 User's Guide:
When you deploy a service in Axis, users may then access your
service's URL with a standard web browser and by appending "?WSDL" to
the end of the URL, they will obtain an automatically-generated WSDL
document which describes your service.
Experimental results suggest that Axis is able to use a combination of the .wsdd deployment descriptor file and compiled Java .class files to generate the corresponding .wsdl for a given service. It's interesting to note that, for example, if you have a public method with a Generics return type such as Map, your generated .wsdl file will not contain the return type - it will contain "xsd:anyType" instead. I believe this is due to type erasure on the compiled .class file.
Anyway, the service options in the Axis .wsdd file (the parameters I referenced in my question such as wsdlPortType, wsdlServicePort, and wsdlTargetNamespace) are related to the .wsdl specifications. This can be inferred from the names themselves since they all contain 'wsdl' in them, but I wanted an explanation of what these parameters mean and I was unable to find relevant Axis documentation. Here are my findings:
wsdlPortType (portType): basically like a Java interface. Contains one "operation" element for each method name. Each "operation" contains "input" and "output" elements that are basically your input parameters and return parameter of the Java method.
wsdlServicePort (wsdl:binding) Associated with the portType. I think of it as a description of how to transmit the parameters for the portType. The spec has this to say:
A binding description component provides a framework for indicating
binding details for a portType description component. Binding details
SHOULD be used to indicate how messages MUST be formatted when they
are sent to or from the service. They SHOULD also be used to indicate
the transport protocol to be used to send the messages. A given
binding description component MUST NOT indicate more than one
protocol.
wsdl:service: Has a reference in it to the wsdl port binding (the implementation of the portType).
target namespace: Pretty much what I thought it was (same as a namespace anywhere else). It applies to all of the wsdl:definitions components, so anything in the wsdl file basically (wsdl:portType, wsdl:service, etc). There are a couple other rules that you can find in the spec though.
Problem:
When using Service?wsdl, the generated wsdl may not have
the same targetNamespace, portType, service element name, or
service port name as the original wsdl. This problem has
been reported by users and is a TCK issue.
Solution:
Four optional parameters are added to the deploy.wsdd and
queried by the JavaProvider (wsdlTargetNamespace, wsdlServiceElement,
wsdlServicePort and wsdlPortType).
Here is an example deploy.wsdd with the new parameters.
<!-- Services from AddressBookService WSDL service -->
<service name="AddressBook" provider="java:RPC">
<parameter name="wsdlTargetNamespace" value="urn:AddressFetcher2"/>
<parameter name="wsdlServiceElement" value="AddressBookService"/>
<parameter name="wsdlServicePort" value="AddressBook"/>
<parameter name="className" value="samples.addr.AddressBookSOAPBindingSkeleton"/>
<parameter name="wsdlPortType" value="AddressBook"/>
<parameter name="allowedMethods" value="*"/>
<parameter name="scope" value="Session"/>
Source: http://mail-archives.apache.org/mod_mbox/axis-java-dev/200206.mbox/%3C20020621143740.41268.qmail#icarus.apache.org%3E
My question is similar to this. How To Pass Soap Header When WSDL Doesn't Define It? But is different.
For a web service I use, all methods need authentication which is sent in cleartext inside a SOAP header. However, my WSDL doesn't include any soap header information. I have a custom platform tool which I must use to generate code from the WSDL. Since the header info is not available, am unable to use the generated class directly - I do not want to manually modify the code to accommodate the header.
I tried specifying the SOAP header in the WSDL but I failed to get the correct namespaces. The WSDL is here https://stage.totalcheck.sensis.com.au/service/webservice?wsdl and the SOAP header is as follows:
<soapenv:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Can someone help me? Thanks!
From a conceptual point of view, WSDL is not supposed to define headers. WSDL is only for defining the functional aspects of a service, like operations, messages, binding and endpoints. Messages and bindings define how the payload of messages should be encoded and formatted.
The headers of SOAP messages however do not belong to the payload. They are typically used for configuring non-functional properties of a SOAP processor. Security is such a non-functional property. The functional aspect of the payload is not affected. It is only assured that the communication is secured and the WS tool stack, not the service implementation, should take care of that.
So the missing piece is now a standard that allows for attaching some non-functional requirements to WSDL services, so that code generators can automatically derive which headers need to be sent and/or understand in order to fulfill the non-functional property as desired -- without having to manually deal with header fields. This standard exists and is called WS-Policy. A policy contains typically a set of alternatives that expose a set of requirements that both, provider and consumer should be able to fulfill. When two services are supposed to interact with each other, both policies are taken and a so called "effective policy" is calculated. It defines the common non-functional requirements. Using this information, provider and consumer can configure themselves to add required headers, like the WS-Security headers. WS-SecurityPolicy also defines a set of policies that can be used. WS-PolicyAttachment defines how such policies can be attached to a WSDL.
There are code generators that can deal with WS-Policies, e.g. Metro or Axis2
You can add soap header information to method calls by decorating the methods in the proxy class generated from the wsdl with the SoapHeader attribute.
For example wsdl.exe will generate client proxy class Reference.cs for the web service reference when you "Add Web Reference". In the link mentioned above https://stage.totalcheck.sensis.com.au/service/webservice?wsdl there is a message suggestAddress which will translate to a method in the generated reference.cs client proxy code file when you add a web reference from visual studio. By default when this method is called there will be no Header in the soap envelope. To add a SoapHeader to the envelope for this request add a [SoapHeader("Security")] attribute to the top of the SuggestAddress method in the Reference.cs generated class, where "Security" is a class that inherits from SoapHeader base class.
Example for the above required Security SoapHeader you would create the following classes,
public partial class Security : SoapHeader
{
public UserNameToken UserNameToken { get; set; }
}
public partial class UserNameToken
{
public string UserName { get; set; }
public string Password { get; set; }
}
Then you would decorate the SuggestAddress method in the reference.cs like followed,
[SoapHeader("Security")]
public suggestAddressesResult suggestAddresses([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] addressSearch search) {
object[] results = this.Invoke("suggestAddresses", new object[] {search});
return ((suggestAddressesResult)(results[0]));
}
This will ensure that every envelope created when method suggestAddress is invoked contains a security header that looks like the one mentioned above,
<soapenv:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
Key for me in using this question to help myself was recognizing (as some pointed out) that the headers in question are those of WS-Security standard.
If your proxy generating tool is "custom" it seems logical that you might have a switch to automatically add the headers for WS-Security. However, if you're using WSDL.exe ("Add Web Reference" in Visual Studio), consider svcutil.exe instead ("Add Service Reference").
If you use a WCF proxy, you can override the given config and allow WCF to add the headers for you:
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
From there you can specify the password:
RemoteSvcProxy.TheirClient client = new RemoteSvcProxy.TheirClient();
client.ClientCredentials.UserName.UserName = "uname";
client.ClientCredentials.UserName.Password = "pwd";
I don't know what your custom tool is, but perhaps the framework it's based on also has similar configuration options.