generate wsdl from legacy jax-ws client code - wsdl

it´s possible to generate a WSDL using the JAX-WS client code only?
I have a legacy client code without wsdl inside, just remote wsdl uri, and I need to create mockservices for that client code and I need the WSDL to create this mocks.
Any idea?

For purpose of creating a mock/stub service provider, I believe it is better to download the original WSDL if you can. The risk with generating a WSDL from client generated code is the definite possibility the generated WSDL doesn't exactly match the original, which defeats the purpose of mocking or stubbing.
However, here were the steps I used to generate a WSDL from a generated JAX-WS client. I did have to hand-code an implementation class.
Original WSDL: http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL
Generate JAX-WS client:
wsimport -extension -keep http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL
This creates the sample JAX-WS client, which includes a generated service endpoint interface (SEI): com.cdyne.ws.weatherws.WeatherSoap
Oddly enough, we need an implementation class to run wsgen to generate a WSDL. I manually created an implementation class, declared it to implement the SEI, then copied all methods from the interface definition and gave each a return null; implementation.
package com.cdyne.ws.weatherws;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
#WebService(name = "WeatherSoap", targetNamespace = "http://ws.cdyne.com/WeatherWS/")
public class WeatherSoapStubImpl implements WeatherSoap {
/**
* Gets Information for each WeatherID
*
* #return
* returns com.cdyne.ws.weatherws.ArrayOfWeatherDescription
*/
#WebMethod(operationName = "GetWeatherInformation", action = "http://ws.cdyne.com/WeatherWS/GetWeatherInformation")
#WebResult(name = "GetWeatherInformationResult", targetNamespace = "http://ws.cdyne.com/WeatherWS/")
#RequestWrapper(localName = "GetWeatherInformation", targetNamespace = "http://ws.cdyne.com/WeatherWS/", className = "com.cdyne.ws.weatherws.GetWeatherInformation")
#ResponseWrapper(localName = "GetWeatherInformationResponse", targetNamespace = "http://ws.cdyne.com/WeatherWS/", className = "com.cdyne.ws.weatherws.GetWeatherInformationResponse")
public ArrayOfWeatherDescription getWeatherInformation() {
return null;
}
/**
* Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only
*
* #param zip
* #return
* returns com.cdyne.ws.weatherws.ForecastReturn
*/
#WebMethod(operationName = "GetCityForecastByZIP", action = "http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP")
#WebResult(name = "GetCityForecastByZIPResult", targetNamespace = "http://ws.cdyne.com/WeatherWS/")
#RequestWrapper(localName = "GetCityForecastByZIP", targetNamespace = "http://ws.cdyne.com/WeatherWS/", className = "com.cdyne.ws.weatherws.GetCityForecastByZIP")
#ResponseWrapper(localName = "GetCityForecastByZIPResponse", targetNamespace = "http://ws.cdyne.com/WeatherWS/", className = "com.cdyne.ws.weatherws.GetCityForecastByZIPResponse")
public ForecastReturn getCityForecastByZIP(
#WebParam(name = "ZIP", targetNamespace = "http://ws.cdyne.com/WeatherWS/")
String zip) {
return null;
}
/**
* Allows you to get your City's Weather, which is updated hourly. U.S. Only
*
* #param zip
* #return
* returns com.cdyne.ws.weatherws.WeatherReturn
*/
#WebMethod(operationName = "GetCityWeatherByZIP", action = "http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP")
#WebResult(name = "GetCityWeatherByZIPResult", targetNamespace = "http://ws.cdyne.com/WeatherWS/")
#RequestWrapper(localName = "GetCityWeatherByZIP", targetNamespace = "http://ws.cdyne.com/WeatherWS/", className = "com.cdyne.ws.weatherws.GetCityWeatherByZIP")
#ResponseWrapper(localName = "GetCityWeatherByZIPResponse", targetNamespace = "http://ws.cdyne.com/WeatherWS/", className = "com.cdyne.ws.weatherws.GetCityWeatherByZIPResponse")
public WeatherReturn getCityWeatherByZIP(
#WebParam(name = "ZIP", targetNamespace = "http://ws.cdyne.com/WeatherWS/")
String zip) {
return null;
}
}
Compile the stub implementation class.
javac com/cdyne/ws/weatherws/WeatherSoapStubImpl.java
Generate the WSDL. This is where command line switches can be used to try to get as close as possible to the original.
wsgen -keep -cp . com.cdyne.ws.weatherws.WeatherSoapStubImpl -wsdl:Xsoap1.2 -extension -inlineSchemas
(creates WSDL in current dir):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#8c29a9a53251ff741fca1664a8221dc876b2eac8. -->
<definitions targetNamespace="http://ws.cdyne.com/WeatherWS/" name="WeatherSoapStubImplService" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:tns="http://ws.cdyne.com/WeatherWS/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
<types>
<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://ws.cdyne.com/WeatherWS/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="GetCityForecastByZIP" type="tns:GetCityForecastByZIP"/>
<xs:element name="GetCityForecastByZIPResponse" type="tns:GetCityForecastByZIPResponse"/>
<xs:element name="GetCityWeatherByZIP" type="tns:GetCityWeatherByZIP"/>
<xs:element name="GetCityWeatherByZIPResponse" type="tns:GetCityWeatherByZIPResponse"/>
<xs:element name="GetWeatherInformation" type="tns:GetWeatherInformation"/>
<xs:element name="GetWeatherInformationResponse" type="tns:GetWeatherInformationResponse"/>
<xs:complexType name="GetWeatherInformation">
<xs:sequence/>
</xs:complexType>
<xs:complexType name="GetWeatherInformationResponse">
<xs:sequence>
<xs:element name="GetWeatherInformationResult" type="tns:ArrayOfWeatherDescription" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ArrayOfWeatherDescription">
<xs:sequence>
<xs:element name="WeatherDescription" type="tns:WeatherDescription" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="WeatherDescription">
<xs:sequence>
<xs:element name="WeatherID" type="xs:short"/>
<xs:element name="Description" type="xs:string" minOccurs="0"/>
<xs:element name="PictureURL" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="GetCityWeatherByZIP">
<xs:sequence>
<xs:element name="ZIP" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="GetCityWeatherByZIPResponse">
<xs:sequence>
<xs:element name="GetCityWeatherByZIPResult" type="tns:WeatherReturn" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="WeatherReturn">
<xs:sequence>
<xs:element name="Success" type="xs:boolean"/>
<xs:element name="ResponseText" type="xs:string" minOccurs="0"/>
<xs:element name="State" type="xs:string" minOccurs="0"/>
<xs:element name="City" type="xs:string" minOccurs="0"/>
<xs:element name="WeatherStationCity" type="xs:string" minOccurs="0"/>
<xs:element name="WeatherID" type="xs:short"/>
<xs:element name="Description" type="xs:string" minOccurs="0"/>
<xs:element name="Temperature" type="xs:string" minOccurs="0"/>
<xs:element name="RelativeHumidity" type="xs:string" minOccurs="0"/>
<xs:element name="Wind" type="xs:string" minOccurs="0"/>
<xs:element name="Pressure" type="xs:string" minOccurs="0"/>
<xs:element name="Visibility" type="xs:string" minOccurs="0"/>
<xs:element name="WindChill" type="xs:string" minOccurs="0"/>
<xs:element name="Remarks" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="GetCityForecastByZIP">
<xs:sequence>
<xs:element name="ZIP" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="GetCityForecastByZIPResponse">
<xs:sequence>
<xs:element name="GetCityForecastByZIPResult" type="tns:ForecastReturn" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ForecastReturn">
<xs:sequence>
<xs:element name="Success" type="xs:boolean"/>
<xs:element name="ResponseText" type="xs:string" minOccurs="0"/>
<xs:element name="State" type="xs:string" minOccurs="0"/>
<xs:element name="City" type="xs:string" minOccurs="0"/>
<xs:element name="WeatherStationCity" type="xs:string" minOccurs="0"/>
<xs:element name="ForecastResult" type="tns:ArrayOfForecast" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ArrayOfForecast">
<xs:sequence>
<xs:element name="Forecast" type="tns:Forecast" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Forecast">
<xs:sequence>
<xs:element name="Date" type="xs:dateTime"/>
<xs:element name="WeatherID" type="xs:short"/>
<xs:element name="Desciption" type="xs:string" minOccurs="0"/>
<xs:element name="Temperatures" type="tns:temp"/>
<xs:element name="ProbabilityOfPrecipiation" type="tns:POP"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="temp">
<xs:sequence>
<xs:element name="MorningLow" type="xs:string" minOccurs="0"/>
<xs:element name="DaytimeHigh" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="POP">
<xs:sequence>
<xs:element name="Nighttime" type="xs:string" minOccurs="0"/>
<xs:element name="Daytime" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</types>
<message name="GetWeatherInformation">
<part name="parameters" element="tns:GetWeatherInformation"/>
</message>
<message name="GetWeatherInformationResponse">
<part name="parameters" element="tns:GetWeatherInformationResponse"/>
</message>
<message name="GetCityForecastByZIP">
<part name="parameters" element="tns:GetCityForecastByZIP"/>
</message>
<message name="GetCityForecastByZIPResponse">
<part name="parameters" element="tns:GetCityForecastByZIPResponse"/>
</message>
<message name="GetCityWeatherByZIP">
<part name="parameters" element="tns:GetCityWeatherByZIP"/>
</message>
<message name="GetCityWeatherByZIPResponse">
<part name="parameters" element="tns:GetCityWeatherByZIPResponse"/>
</message>
<portType name="WeatherSoap">
<operation name="GetWeatherInformation">
<input wsam:Action="http://ws.cdyne.com/WeatherWS/GetWeatherInformation" message="tns:GetWeatherInformation"/>
<output wsam:Action="http://ws.cdyne.com/WeatherWS/WeatherSoap/GetWeatherInformationResponse" message="tns:GetWeatherInformationResponse"/>
</operation>
<operation name="GetCityForecastByZIP">
<input wsam:Action="http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP" message="tns:GetCityForecastByZIP"/>
<output wsam:Action="http://ws.cdyne.com/WeatherWS/WeatherSoap/GetCityForecastByZIPResponse" message="tns:GetCityForecastByZIPResponse"/>
</operation>
<operation name="GetCityWeatherByZIP">
<input wsam:Action="http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP" message="tns:GetCityWeatherByZIP"/>
<output wsam:Action="http://ws.cdyne.com/WeatherWS/WeatherSoap/GetCityWeatherByZIPResponse" message="tns:GetCityWeatherByZIPResponse"/>
</operation>
</portType>
<binding name="WeatherSoapPortBinding" type="tns:WeatherSoap">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="GetWeatherInformation">
<soap12:operation soapAction="http://ws.cdyne.com/WeatherWS/GetWeatherInformation"/>
<input>
<soap12:body use="literal"/>
</input>
<output>
<soap12:body use="literal"/>
</output>
</operation>
<operation name="GetCityForecastByZIP">
<soap12:operation soapAction="http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP"/>
<input>
<soap12:body use="literal"/>
</input>
<output>
<soap12:body use="literal"/>
</output>
</operation>
<operation name="GetCityWeatherByZIP">
<soap12:operation soapAction="http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP"/>
<input>
<soap12:body use="literal"/>
</input>
<output>
<soap12:body use="literal"/>
</output>
</operation>
</binding>
<service name="WeatherSoapStubImplService">
<port name="WeatherSoapPort" binding="tns:WeatherSoapPortBinding">
<soap12:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>
Create the stub or mock service with tooling such as SOAPUI
With this approach and simple service interface I was able to successfully send SOAP messages with the client to a mock service provider created in SOAPUI created with the generated WSDL.

Related

Conditional Assignment in XSD1.1

I have difficulty in writing a schema in XSD1.1. XML structure is already defined and used by many teams, so changing the xml is not an option to me.
May be I can't explain everything I tried here. XSD has evolved so much since start. I just hope some ppl can understand the problem clearly.. Would be great if someone can share their way of solving this problems..
How XML looks like (in simplified format)
<Node>
<Create Type="A">
<Attr Name="Type1" Val="123"/>
<Attr Name="Type2" Val="Water"/>
<Attr Name="Type3" Val="2019-12-01T08:00:00"/>
</Create>
<Create Type="B">
<Attr Name="TypeM" Val="OB123"/>
<Attr Name="Type2" Val="Fire"/>
<Attr Name="TypeK" Val="2019-12-01T08:00:00"/>
<Attr Name="TypeN" Val="11.567"/>
</Create>
</Node>
Problem:
Based on "Type" attribute in Element<Create> - Number of <Attr> Elements changes (There are 80 types). Each Type can allow specific set of child attr. In above e.g, when Type = A, it can have only 3 children and specifically Type1, Type2 and Type3.
Based on value of "Name" attribute in Element <Attr> , attribute "Val" can have range of Values. In Xml shown above, Type2 can have {Fire, Water}
Based on value of "Name" attribute in Element<Attr> , define the type of second attribute "Val" which can be (date,integer, string, float etc)
The XSD I am trying to write looks something like this (actual XSD and XML are huge)..
<xs:element name="Node" type="NodeType"/>
<xs:complexType name="NodeType">
<xs:sequence>
<xs:element name="Create">
<xs:alternative test="#Type = 'A'" type="AType"/>
<xs:alternative test="#Type = 'B'" type="BType"/>
<xs:alternative type="xs:error"/>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AType">
<xs:sequence>
<xs:element name="Attr">
<xs:alternative test="#Name = 'Type1'" type="AttrType1"/>
<xs:alternative test="#Name = 'Type2'" type="AttrType2"/>
<xs:alternative test="#Name = 'Type3'" type="AttrType3"/>
<!--<xs:alternative type="xs:error"/> This line gives error while same line above passes validation-->
</xs:element>
</xs:sequence>
<xs:attribute name="Type" use="required" type="AllowedTypes"/> <!-- AllowedTypes is an enum of 80 values-->
<xs:assert test="(#Type = 'A')"/>
</xs:complexType>
<xs:complexType name="AttrType1">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="AttrType2">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:string"/>
<xs:assert test="(#Val = 'Fire' or #Val='Water')"/>
</xs:complexType>
<xs:complexType name="AttrType3">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:dateTime"/>
</xs:complexType>
<!-- Similarly written for BType -->
Thanks to this post - How to make type depend on attribute value using Conditional Type Assignment.
After spending days.. I am able to solve 3 problems (one at a time) stated above.. I am facing issue when I tried to club all 3 solutions in one nice compact xsd.
For Eg.. When I try to solve Problem 3, solution to problem 1 is messed up.
<Node>
<Create Type="A">
<Attr Name="Type1" Val="123"/>
<Attr Name="Type2" Val="Water"/>
<Attr Name="TypeZ" Val="2019-12-01T08:00:00"/>
</Create>
</Node>
<!-- I want XSD to throw error saying TypeZ is not allowed -->
I rectified xsd to solve all prob statements
<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
xmlns:xerces="http://xerces.apache.org"
vc:minVersion="1.1">
<xs:element name="Node" type="NodeType"/>
<xs:complexType name="NodeType">
<xs:sequence>
<xs:element name="Create" maxOccurs="5">
<xs:alternative test="#Type = 'A'" type="AType"/>
<xs:alternative test="#Type = 'B'" type="BType"/>
<xs:alternative type="xs:error"/>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AType">
<xs:sequence>
<xs:element name="Attr" maxOccurs="3">
<xs:alternative test="#Name = 'Type1'" type="AttrType1"/>
<xs:alternative test="#Name = 'Type2'" type="AttrType2"/>
<xs:alternative test="#Name = 'Type3'" type="AttrType3"/>
<xs:alternative type="xs:error"/>
</xs:element>
</xs:sequence>
<xs:attribute name="Type" use="required" type="xs:string"/>
<xs:assert test="(#Type = 'A')"/>
</xs:complexType>
<xs:complexType name="AttrType1">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="AttrType2">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:string"/>
<xs:assert test="(#Val = 'Fire' or #Val = 'Water')"/>
</xs:complexType>
<xs:complexType name="AttrType3">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:dateTime"/>
</xs:complexType>
<!-- Similarly written for BType -->
<xs:complexType name="BType">
<xs:sequence>
<xs:element name="Attr" maxOccurs="4">
<xs:alternative test="#Name = 'TypeM'" type="AttrTypeM"/>
<xs:alternative test="#Name = 'Type2'" type="AttrType2"/>
<xs:alternative test="#Name = 'TypeK'" type="AttrTypeK"/>
<xs:alternative test="#Name = 'TypeN'" type="AttrTypeN"/>
<xs:alternative type="xs:error"/>
</xs:element>
</xs:sequence>
<xs:attribute name="Type" use="required" type="xs:string"/>
<xs:assert test="(#Type = 'B')"/>
</xs:complexType>
<xs:complexType name="AttrTypeM">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:string"/>
</xs:complexType>
<xs:complexType name="AttrTypeK">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:dateTime"/>
</xs:complexType>
<xs:complexType name="AttrTypeN">
<xs:attribute name="Name" type="xs:string"/>
<xs:attribute name="Val" type="xs:float"/>
</xs:complexType>
</xs:schema>

XSLT - How to tell if an element with specific attribute value is the last in the matching series

I have the following XSLT template
<xsl:template match="xsd:element[#name != '' and not(starts-with(#type, 'common:'))]">
<xsl:if test="position() != last()">
"<xsl:value-of select="#name"/>",
</xsl:if>
<xsl:if test="position() = last()">
"<xsl:value-of select="#name"/>"
</xsl:if>
</xsl:template>
that tries to match all elements with non empty name and it's type doesn't start with 'common:' then it will generate a comma separated list of these elements names.
so if applied to
<xsd:element name="One" type="String"/>
<xsd:element name="" type="String"/>
<xsd:OtherNode />
<xsd:element name="Two" type="common:Characters"/>
<xsd:element name="Three" type="Long"/>
<xsd:OtherNode />
it should generate
"One",
"Three"
notice that there is no comma after "Three"
but it sounds like there is something wrong with position() and last() as when printing its values it doesn't sounds to be correct and there is always a comma ','
"One",
"Three",
a complete sample of an input XML that will be processed by the XSLT is an XSD something like
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="[h t t p] ://www.w3.org/2001/XMLSchema"
xmlns:common="[http]://abc.com/common/1.0">
<!-- definition of simple elements -->
<xsd:element name="orderperson" type="xsd:string"/>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="address" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="country" type="xsd:string"/>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="note" type="xsd:string"/>
<xsd:element name="quantity" type="xsd:positiveInteger"/>
<xsd:element name="price" type="common:decimal"/>
<!-- definition of complex elements -->
<xsd:complexType name="shipto">
<xsd:sequence>
<xsd:element ref="name"/>
<xsd:element ref="address"/>
<xsd:element ref="city"/>
<xsd:element ref="country"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="item">
<xsd:sequence>
<xsd:element ref="title"/>
<xsd:element ref="note" minOccurs="0"/>
<xsd:element ref="quantity"/>
<xsd:element ref="price"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="shiporder">
<xsd:sequence>
<xsd:element ref="orderperson"/>
<xsd:element ref="shipto"/>
<xsd:element ref="item" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
and below is part of my XSLT after removing unrelated sections to keep it short
<xsl:stylesheet version="2.0"
xmlns:xsl="[http]://www.w3.org/1999/XSL/Transform"
xmlns:xsd="[http]://www.w3.org/2001/XMLSchema"
xmlns:xml="[http]://www.w3.org/XML/1998/namespace"
xmlns:common="[http]://abc.com/common/1.0">
<xsl:output method="text" media-type="text/xml" indent="yes" encoding="ISO-8859-1" />
<xsl:template match="/">
<xsl:call-template name="pre-properties"/>
<xsl:apply-templates/>
<xsl:call-template name="post-properties"/>
</xsl:template>
<xsl:template match="/xsd:schema/xsd:complexType/xsd:sequence/xsd:element"/>
<xsl:template name="pre-properties">
{
<xsl:template name="post-properties">
}
</xsl:template>
<xsl:template match="xsd:element[#name != '' and not(starts-with(#type, 'common:'))]">
<xsl:if test="position() != last()">
"<xsl:value-of select="#name"/>",
</xsl:if>
<xsl:if test="position() = last()">
"<xsl:value-of select="#name"/>"
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Move the check into a predicate e.g.
<xsl:template match="xsd:element[#name != '' and not(starts-with(#type, 'common:'))][position() != last()]">
"<xsl:value-of select="#name"/>",
</xsl:template>
<xsl:template match="xsd:element[#name != '' and not(starts-with(#type, 'common:'))][position() = last()]">
"<xsl:value-of select="#name"/>"
</xsl:template>
Or you might simply try
<xsl:value-of select="//xsd:element[#name != '' and not(starts-with(#type, 'common:'))]/concat('"', #name, '"')" separator=", "/>
where you want to output those values.

Use Sabre SOAP API with iOS

Does anyone know how to use sabre SOAP web services with IOS? anyone has done that ? I am using AFNetworking for the network call.
I am using AFHTTPRequestOperation to make a call to web service but that web service require authentication.
Authentication parameters are username , password , and IPCC. I can set username and password by
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"aaaaa" password:#"aaaaaa" persistence:NSURLCredentialPersistenceNone];
[operation setCredential:credential];
but how can set that IPCC parameter?
Something like (quick and dirty):
NSString *soapMessage = [NSString stringWithFormat:
#"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:eb=\"http://www.ebxml.org/namespaces/messageHeader\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"
" <SOAP-ENV:Header>"
" <eb:MessageHeader SOAP-ENV:mustUnderstand=\"1\" eb:version=\"1.0\">"
" <eb:ConversationId/>"
" <eb:From>"
" <eb:PartyId type=\"urn:x12.org:IO5:01\">999999</eb:PartyId>"
" </eb:From>"
" <eb:To>"
" <eb:PartyId type=\"urn:x12.org:IO5:01\">123123</eb:PartyId>"
" </eb:To>"
" <eb:CPAId>IPCC</eb:CPAId>"
" <eb:Service eb:type=\"OTA\">SessionCreateRQ</eb:Service>"
" <eb:Action>SessionCreateRQ</eb:Action>"
" <eb:MessageData>"
" <eb:MessageId>1000</eb:MessageId>"
" <eb:Timestamp>2001-02-15T11:15:12Z</eb:Timestamp>"
" <eb:TimeToLive>2001-02-15T11:15:12Z</eb:TimeToLive>"
" </eb:MessageData>"
" </eb:MessageHeader>"
" <wsse:Security xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xmlns:wsu=\"http://schemas.xmlsoap.org/ws/2002/12/utility\">"
" <wsse:UsernameToken>"
" <wsse:Username>%#</wsse:Username>"
" <wsse:Password>%#</wsse:Password>"
" <Organization>%#</Organization>"
" <Domain>DEFAULT</Domain>"
" </wsse:UsernameToken>"
" </wsse:Security>"
" </SOAP-ENV:Header>"
" <SOAP-ENV:Body>"
" <eb:Manifest SOAP-ENV:mustUnderstand=\"1\" eb:version=\"1.0\">"
" <eb:Reference xmlns:xlink=\"http://www.w3.org/1999/xlink\" xlink:href=\"cid:rootelement\" xlink:type=\"simple\"/>"
" </eb:Manifest>"
" </SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>"
,username
,password
,ipccValue
];
I assume you mean the ipccValue in the Organization block, rather than the eb:CPAId block
from https://developer.sabre.com/docs/read/soap_basics/Authentication
and credits to send parameter in soap web service from ios
When i tried the above snippet its returning me this
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd1="http://www.opentravel.org/OTA/2002/11" xmlns:tns="https://webservices.sabre.com/websvc" xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" targetNamespace="https://webservices.sabre.com/websvc">
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://www.opentravel.org/OTA/2002/11" schemaLocation="SessionCreateRQRS.xsd"/>
<xsd:import namespace="http://www.ebxml.org/namespaces/messageHeader" schemaLocation="msg-header-2_0.xsd"/>
<xsd:import namespace="http://schemas.xmlsoap.org/ws/2002/12/secext" schemaLocation="wsse.xsd"/>
</xsd:schema>
</types>
<message name="GetSessionCreateInput">
<part name="header" element="eb:MessageHeader"/>
<part name="header2" element="wsse:Security"/>
<part name="body" element="xsd1:SessionCreateRQ"/>
</message>
<message name="GetSessionCreateOutput">
<part name="header" element="eb:MessageHeader"/>
<part name="header2" element="wsse:Security"/>
<part name="body" element="xsd1:SessionCreateRS"/>
</message>
<portType name="SessionCreatePortType">
<operation name="SessionCreateRQ">
<input message="tns:GetSessionCreateInput"/>
<output message="tns:GetSessionCreateOutput"/>
</operation>
</portType>
<binding name="SessionCreateSoapBinding" type="tns:SessionCreatePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="SessionCreateRQ">
<soap:operation soapAction="OTA"/>
<input>
<soap:header message="tns:GetSessionCreateInput" part="header" use="literal"/>
<soap:header message="tns:GetSessionCreateInput" part="header2" use="literal"/>
<soap:body parts="body" use="literal"/>
</input>
<output>
<soap:header message="tns:GetSessionCreateOutput" part="header" use="literal"/>
<soap:header message="tns:GetSessionCreateOutput" part="header2" use="literal"/>
<soap:body parts="body" use="literal"/>
</output>
</operation>
</binding>
<service name="SessionCreateRQService">
<port name="SessionCreatePortType" binding="tns:SessionCreateSoapBinding">
<soap:address location="https://webservices.sabre.com"/>
</port>
</service>
</definitions>

context.Trigger.JobDataMap values via xml configuration

In quartz_jobs.xml, I can set some parameters for the job.....
<job>
<name>MyJob</name>
<group>MyJob</group>
<description>My Job</description>
<job-type>MyAssembly.MyJob, MyAssembly</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>JobMapDataKeyOne</key>
<value>JobMapDataValueOne</value>
</entry>
<entry>
<key>JobMapDataKeyTwo</key>
<value>JobMapDataValueTwo</value>
</entry>
</job-data-map>
</job>
and here is the code:
public class MyJob: IJob
{
public virtual void Execute(IJobExecutionContext context)
{
JobKey key = context.JobDetail.Key;
JobDataMap jbDataMap = context.JobDetail.JobDataMap;
string jobMapDataValueOne = jbDataMap.GetString("JobMapDataKeyOne");
string jobMapDataValueTwo = jbDataMap.GetString("JobMapDataKeyOne");
}
}
Now, I can "code up a job and trigger" (not using .xml setup) (code not seen).... and I can get the below to work.
(And have populated values for triggerParameter001Value and triggerParameter002Value ).
public class MyJob: IJob
{
public virtual void Execute(IJobExecutionContext context)
{
JobKey key = context.JobDetail.Key;
JobDataMap trgDataMap = context.Trigger.JobDataMap;
string triggerParameter001Value = trgDataMap.GetString("TriggerParameter001Key");
string triggerParameter002Value = trgDataMap.GetString("TriggerParameter002Key");
}
}
But I don't see a way to pass parameters for the Trigger...defined in the xml.
I searched for
"trigger-data-map"
and
"jobtrigger-data-map"
to no avail.
I fished around the "http://quartznet.sourceforge.net/JobSchedulingData" xsd as well.
Is this just missing in the xml?
Am I missing something?
Ok. This one was SNEAKY!
The below will NOT work: (note the position of "job-data-map" element ~under the "simple" element)
<job>
<name>MyJob</name>
<group>MyJobGroup</group>
<description>My Job</description>
<job-type>MyAssembly.MyJob, MyAssembly</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>JobMapDataKeyOne</key>
<value>JobMapDataValueOne</value>
</entry>
<entry>
<key>JobMapDataKeyTwo</key>
<value>JobMapDataValueTwo</value>
</entry>
</job-data-map>
</job>
<trigger>
<simple>
<name>MyTrigger</name>
<group>MyTriggerJobGroup</group>
<description>MyTriggerDescription</description>
<job-name>MyJob</job-name>
<job-group>MyJobGroup</job-group>
<!--<start-time>1982-06-28T18:15:00.0Z</start-time>-->
<!--<end-time>2020-05-04T18:13:51.0Z</end-time>-->
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- repeat indefinitely every 10 seconds -->
<repeat-count>-1</repeat-count>
<repeat-interval>5000</repeat-interval>
<job-data-map>
<entry>
<key>TriggerParameter001Key</key>
<value>TriggerParameter001Value</value>
</entry>
<entry>
<key>TriggerParameter002Key</key>
<value>TriggerParameter002Value</value>
</entry>
</job-data-map>
</simple>
</trigger>
The above xml was giving me an error like this:
Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin.ProcessFile Error Error scheduling jobs: The element 'simple' in namespace 'http://quartznet.sourceforge.net/JobSchedulingData' has invalid child element 'job-data-map' in namespace 'http://quartznet.sourceforge.net/JobSchedulingData'.
........................
The below WILL work (note the position change of "job-data-map" (still under "simple" element, but moved "up" some)
<job>
<name>MyJob</name>
<group>MyJobGroup</group>
<description>My Job</description>
<job-type>MyAssembly.MyJob, MyAssembly</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>JobMapDataKeyOne</key>
<value>JobMapDataValueOne</value>
</entry>
<entry>
<key>JobMapDataKeyTwo</key>
<value>JobMapDataValueTwo</value>
</entry>
</job-data-map>
</job>
<trigger>
<simple>
<name>MyTrigger</name>
<group>MyTriggerJobGroup</group>
<description>MyTriggerDescription</description>
<job-name>MyJob</job-name>
<job-group>MyJobGroup</job-group>
<job-data-map>
<entry>
<key>TriggerParameter001Key</key>
<value>TriggerParameter001Value</value>
</entry>
<entry>
<key>TriggerParameter002Key</key>
<value>TriggerParameter002Value</value>
</entry>
</job-data-map>
<!--<start-time>1982-06-28T18:15:00.0Z</start-time>-->
<!--<end-time>2020-05-04T18:13:51.0Z</end-time>-->
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- repeat indefinitely every 10 seconds -->
<repeat-count>-1</repeat-count>
<repeat-interval>5000</repeat-interval>
</simple>
</trigger>
Why?
The xsd uses an abstractType
<xs:complexType name="abstractTriggerType" abstract="true">
<xs:annotation>
<xs:documentation>Common Trigger definitions</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="group" type="xs:string" minOccurs="0" />
<xs:element name="description" type="xs:string" minOccurs="0" />
<xs:element name="job-name" type="xs:string" />
<xs:element name="job-group" type="xs:string" minOccurs="0" />
<xs:element name="priority" type="xs:nonNegativeInteger" minOccurs="0" />
<xs:element name="calendar-name" type="xs:string" minOccurs="0" />
<xs:element name="job-data-map" type="job-data-mapType" minOccurs="0" />
<xs:complexType name="simpleTriggerType">
<xs:annotation>
<xs:documentation>Define a SimpleTrigger</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:extension base="abstractTriggerType">
<xs:sequence>
<xs:element name="misfire-instruction" type="simple-trigger-misfire-instructionType" minOccurs="0" />
<xs:sequence minOccurs="0">
<xs:element name="repeat-count" type="repeat-countType" />
<xs:element name="repeat-interval" type="xs:nonNegativeInteger" />
</xs:sequence>
So everything that is a part of the abstract has to be defined ~before~ any of the concrete properties.
That is sneaky!

Return type in wsimport-generated service stub methods

Here is an example of wsimport-generated service stub method:
#WebMethod(operationName = "GetSynonym", action = "GetSynonymRequest")
#WebResult(name = "Synonyms", targetNamespace = "service.bnsf.com/contact/ContactMessages")
#RequestWrapper(localName = "GetSynonym", targetNamespace = "service.bnsf.com/contact/ContactMessages", className = "com.bnsf.service.contact.contactmessages.GetSynonymRequest")
#ResponseWrapper(localName = "GetSynonymResponse", targetNamespace = "service.bnsf.com/contact/ContactMessages", className = "com.bnsf.service.contact.contactmessages.GetSynonymResponse")
public Synonyms getSynonym(
#WebParam(name = "RequestContext", targetNamespace = "service.bnsf.com/contact/ContactMessages") RequestContext requestContext,
#WebParam(name = "SynonymId", targetNamespace = "service.bnsf.com/contact/ContactMessages") EntityId synonymId)
throws BusinessFaultMessage, ServiceFaultMessage;
Note that return type is Synonyms class.
Here are the relevant wsdl parts:
<xs:element name="GetSynonymResponse" type="GetSynonymResponse"/>
<xs:complexType name="GetSynonymResponse">
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="1" name="Synonyms" type="account:Synonyms"/>
</xs:sequence>
</xs:complexType>
...
<wsdl:message name="GetSynonymResponse">
<wsdl:part element="msg:GetSynonymResponse" name="GetSynonymResponse"/>
</wsdl:message>
...
<wsdl:operation name="GetSynonym">
<soap:operation soapAction="GetSynonymRequest" style="document"/>
<wsdl:input name="GetSynonymRequestRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="GetSynonymRequestResponse">
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="BusinessFault">
<soap:fault name="BusinessFault" use="literal"/>
</wsdl:fault>
<wsdl:fault name="ServiceFault">
<soap:fault name="ServiceFault" use="literal"/>
</wsdl:fault>
</wsdl:operation>
By default wsimport has generated service method with Synonyms class as return type rather than GetSynonymResponse class.
My question is whether this is customizable - is there a possibility to make wsimport generate service methods with different signatures, particularly having GetSynonymResponse class as return type?
Thanks in advance,
Valery
Found how this is configurable:
The feature called "WrapperStyle" should be disabled to make generated method return xxxResponse type.
This is accomplishable by providing -b parameter to wsimport like
wsimport" -b binding.xml ContactService.wsdl
with binding.xml contents as
<jaxws:bindings wsdlLocation="ContactService.wsdl"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<!-- Turn off wrapper style Java method signature generation -->
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
</jaxws:bindings>

Resources