Showing posts with label wsdl. Show all posts
Showing posts with label wsdl. Show all posts

Thursday, December 9, 2010

Bottom-up, top-down, meet-in-the-middle...

nice article on WSDL design - it makes sense and it's practical...

http://www.ibm.com/developerworks/architecture/library/ar-servdsgn1/

Monday, December 6, 2010

Non unique body parts!

If you get this message, you better fix it, don't rely on SOAPAction for dispatching. Every operation should have a unique body structure, carrying as root element the operation name.

Most likely, the mistake has been:
declaring multiple wsdl:message with the same "part" structure.
See here for a template you can use to write your WSDL.

I know, WSDL are a pain in the neck, especially the 1.1 version.

Wednesday, June 9, 2010

HelloWorld WSDL

Need a quick WSDL to make a dummy Web Service? Here you are:




  
    
      
        
          
            
          
        
      
      
        
          
            
          
        
      
    
  
  
    
  
  
    
  
  
    
      
      
    
  
  
    
    
      
      
        
      
      
        
      
    
  
  
    
      
    
  
 



Friday, May 7, 2010

Exception Handling in Web Services.... AKA Web Services suck - big time.

I have a WebService with a WebMethod

@WebMethod
public void updateCompany(Company company) throws CompanyException


where
public class CompanyException extends Exception


this generates this WSDL:

    <s0:operation name="updateCompany" parameterOrder="parameters">
      <s0:input message="s1:updateCompany"/>
      <s0:output message="s1:updateCompanyResponse"/>
      <s0:fault message="s1:CompanyException" name="CompanyException"/>
    </s0:operation>

______________________

If I have 2 exceptions:
public void updateCompany(Company company) throws CompanyException, NamingException

I get 2 faults
      <s0:fault message="s1:CompanyException" name="CompanyException"/>
      <s0:fault message="s1:NamingException" name="NamingException"/>

______________________

If I add the annotation javax.xml.ws.WebFault:
@WebFault(name="companyFault")

before the public class CompanyException extends Exception, the WSDL SHOULD become

    <s0:operation name="updateCompany" parameterOrder="parameters">
      <s0:input message="s1:updateCompany"/>
      <s0:output message="s1:updateCompanyResponse"/>
      <s0:fault message="s1:companyFault" name="companyFault"/>
    </s0:operation>

or something like that.... but unfortunately with WebLogic this doesn't seem to affect the WSDL!

______________________

Anyhow, if you construct the CompanyException without invoking the super(String message) constructor,
you will get this:

<env:Body>

<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring/>

<detail>
<com:string xsi:nil="true"/>
</detail>
</env:Fault>
</env:Body>




otherwise, if you do super(message),and you invoke

Java:
throw new CompanyException("UNABLE_TO_EXECUTE_SQL")

SOAP Fault:

<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>UNABLE_TO_EXECUTE_SQL</faultstring>

<detail>
<com:string>UNABLE_TO_EXECUTE_SQL</com:string>
</detail>
</env:Fault>
</env:Body>


______________________

If your exception extends WebServiceException, AND you do super(message), you get something really exciting:


<env:Body>

<env:Fault>
<faultcode>env:Server</faultcode>

<faultstring>
Failed to invoke end component com.acme.dbaccess.CompanyDBWS (POJO), operation=insertCompany
 -> Failed to invoke method
 -> UNABLE_TO_EXECUTE_SQL
</faultstring>

<detail>

<bea_fault:stacktrace>
com.acme.dbaccess.CompanyException: UNABLE_TO_EXECUTE_SQL

    at com.acme.dbaccess.CompanyDBWS.insertCompany(CompanyDBWS.java:81)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
..................
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

</bea_fault:stacktrace>
</detail>
</env:Fault>
</env:Body>



Better still if you use the super(message, Throwable) so you get also the stacktrace of the original exception!

YET the fault generated is not very usable.... the faultstring is very dirty and the faultcode useless....
I need to find a better way of doing this...


______________________


Now, if your service throws an Unchecked Exception (like NullPointerException), you will still get something decent:

Java:
throw new NullPointerException("I am a NPE") ;

SOAP Fault:

<env:Envelope>

<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>
Failed to invoke end component com.acme.dbaccess.CompanyDBWS (POJO), operation=updateCompany
 -> Failed to invoke method
 -> I am a NPE
</faultstring>
<detail>
<bea_fault:stacktrace>
java.lang.NullPointerException: I am a NPE

    at com.acme.dbaccess.CompanyDBWS.updateCompany(CompanyDBWS.java:25)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
..............
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

</bea_fault:stacktrace>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>


_____________________________

If I extend CompanyException from SOAPException, I get this fault:

<env:Envelope>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>UNABLE_TO_UPDATE</faultstring>
<detail>
<java:CompanyException/>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>

that is, the Fault message is cleary readable (UNABLE_TO_UPDATE) but I have lost the Stacktrace.

_____________________________

On the whole, my impression is that Exception (Fault) generation and handling is, as everything else in WS, very poorly specified and implemented. Compare it to the level of technology in Java and you will only cry and feel lost in hyperspace with WS.

Let's face it, when you come from a Java background, you feel that Web Service technology has been designed by a bunch of fat old drunkards in a brothel running wildly after some young cheerful ladies in pink pajamas... two organs require a lot of blood: the brain and the penis, and we can only operate one at a time.

_______________

It is very educational to look at how a SOAP call is executed inside WebLogic:

    JavaClassComponent.invoke(String, Object[], MessageContext) line: 124   
    ComponentHandler.handleRequest(MessageContext) line: 84   
    HandlerIterator.handleRequest(MessageContext, int) line: 141   
    ServerDispatcher.dispatch() line: 114   
    WsSkel.invoke(Connection, WsPort) line: 80   
    SoapProcessor.handlePost(BaseWSServlet, HttpServletRequest, HttpServletResponse) line: 66   
    SoapProcessor.process(HttpServletRequest, HttpServletResponse, BaseWSServlet) line: 44   
    BaseWSServlet$AuthorizedInvoke.run() line: 285   
    WebappWSServlet(BaseWSServlet).service(HttpServletRequest, HttpServletResponse) line: 169   
    WebappWSServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 820   
    StubSecurityHelper$ServletServiceAction.run() line: 227   
    StubSecurityHelper.invokeServlet(ServletRequest, HttpServletRequest, ServletRequestImpl, ServletResponse, HttpServletResponse, Servlet) line: 125   
    ServletStubImpl.execute(ServletRequest, ServletResponse, FilterChainImpl) line: 292   
    ServletStubImpl.execute(ServletRequest, ServletResponse) line: 175   
    WebAppServletContext$ServletInvocationAction.run() line: 3498   
    AuthenticatedSubject.doAs(AbstractSubject, PrivilegedAction) line: 321   
    SecurityManager.runAs(AuthenticatedSubject, AuthenticatedSubject, PrivilegedAction) line: not available   
    WebAppServletContext.securedExecute(HttpServletRequest, HttpServletResponse, boolean) line: 2180   
    WebAppServletContext.execute(ServletRequestImpl, ServletResponseImpl) line: 2086   
    ServletRequestImpl.run() line: 1406   
    ExecuteThread.execute(Runnable) line: 201   
    ExecuteThread.run() line: 173   

MOST LIKELY it's the SoapProcessor who maps the Java Exception to the SOAP Fault.... ah, if only I had the source code!
_______________

JAX-WS specs define at least 4 exceptions (see http://www.ibm.com/developerworks/webservices/library/ws-jaxws-faults/index.html):

SOAPFaultException
javax.xml.ws.WebServiceException
ExecutionException
javax.xml.soap.SOAPException (one is redefined also in XMLBeans)


all this is simply ridiculous. Things have seriously gone out of control in WS technology.   

This post http://io.typepad.com/eben_hewitt_on_java/2009/07/using-soap-faults-and-exceptions-in-java-jaxws-web-services.html  is excellent, yet I keep HATING this technology. I am a strong believer of Convention Over Configuration and when I see all the verbosity in WS it makes me mad.

If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. (Weinberg's Second Law)


Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. (Antoine de Saint-Exupery, French writer)





Thursday, May 6, 2010

Documenting your WSDL and WSDs

DocFlex/XML - XSDDoc - XML Schema Documentation Generator 


http://www.filigris.com/products/docflex_xml/xsddoc/

The command line options are here

http://www.filigris.com/products/docflex_xml/docs/generator.php#cmdline


A sample "silent mode" generation command line is (for Widows):

@echo off
set JAVA_HOME=C:\bea1035\jdk160_24
set DFH=%~dp0
if %DFH:~-1%==\ set DFH=%DFH:~0,-1%
set JAVA_OPTIONS=-Xms256m -Xmx512m
set CLASS_PATH=%DFH%\lib\xml-apis.jar;%DFH%\lib\xercesImpl.jar;%DFH%\lib\resolver.jar;%DFH%\lib\docflex-xml.jar
"%JAVA_HOME%\bin\java" %JAVA_OPTIONS% -cp "%CLASS_PATH%" com.docflex.xml.Generator -config config/generator.config -nodialog



where the generator.config contains:

#Sat Mar 17 23:41:30 CET 2012
output.dir=../out
output.format=HTML
output.launchViewer=false
template.1=../templates/XSDDoc/FramedDoc.tpl
template.2=../templates/XSDDoc/PlainDoc.tpl
template.3=../templates/XMLDoc/PlainDoc.tpl
template.4=../templates/XMLDoc/FramedDoc.tpl
template.5=../samples/sales/sales.tpl
template.6=../samples/personal/personal.tpl
xml.catalogs=urn\:docflex-com\:xml\:defaultcatalog
xml.files.1=../../acme/sss/ssssvn/SSS_CommonServices/Schemas/Service/ShopOrderService.xsd
xml.files.2=../../acme/sss/nesoawsdl/ShopOrderService.xsd
xml.files.3=http\://www.w3.org/2001/XMLSchema.xsd
xml.files.4=../samples/HumanEvolution/HumanEvolution.xsd
xml.files.5=../samples/sales/sales.xml
xml.files.6=../samples/sales/sales.xsd
xml.files.7=../samples/personal/personal.xml



(this will generate only xml.files.1, all the rest seems to be ignored)

what you need to set is:
output.dir -> where to write the generated HTML
xml.files.1 -> the root XSD to parse

Sunday, May 2, 2010

WebLogic WSDL generation

When WL recognizes a WS as a "WebLogic Web Service", it generates the WSDL in a single .wsdl file.
If it recognizes the WS as a plain "JAX-WS Web Service", it generates a .wsdl file AND a .xsd file with the parameters in the XSD.

Needless to say, I prefer having the parameters factored out in the .XSD file, and using an import:

  <types>
    <xsd:schema>
      <xsd:import namespace="http://ws.testws.com/" schemaLocation="WSExceptionHandlingService_schema1.xsd"/>
    </xsd:schema>
  </types>


Another difference, for JAX-WS WebLogic doesn't populate the address element in the WSDL.

Saturday, February 20, 2010

WSDL sucks - anatomy of a WSDL, WSDL for dummies

A very good presentation on the differences between WSDL 1.1 and 2.0 is here
http://people.apache.org/~hughesj/woden/WodenWSDL2Processor_WE12.pdf

This is a sample WSDL 2.0 file:

service has binding, binding has interface, interface has operations, operation has input and output (and fault)


<?xml  version="1.0" encoding="UTF-8"?>
<wsdl:description targetNamespace="http://new.webservice.namespace" xmlns:wsdl="http://www.w3.org/ns/wsdl" xmlns:wsoap="http://www.w3.org/ns/wsdl/soap" xmlns:whttp="http://www.w3.org/ns/wsdl/http" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://new.webservice.namespace">
    <wsdl:types>
        <xs:schema targetNamespace="http://new.webservice.namespace" elementFormDefault="qualified">
            <xs:element name="NewMessageRequest" type="xs:string"/>
            <xs:element name="NewMessageResponse" type="xs:string"/>
        </xs:schema>
    </wsdl:types>
    <wsdl:interface name="NewInterface">
        <wsdl:operation name="NewOperation" pattern="http://www.w3.org/ns/wsdl/in-out">
            <wsdl:input messageLabel="In" element="tns:NewMessageRequest"/>
            <wsdl:output messageLabel="Out" element="tns:NewMessageResponse"/>
        </wsdl:operation>
    </wsdl:interface>
    <wsdl:binding name="NewBinding" interface="tns:NewInterface" type="http://www.w3.org/ns/wsdl/soap" wsoap:protocol="http://www.w3.org/2003/05/soap/bindings/HTTP/">
        <wsdl:operation ref="tns:NewOperation" wsoap:mep="http://www.w3.org/2003/05/soap/mep/request-response/"/>
    </wsdl:binding>
    <wsdl:service name="NewService" interface="tns:NewInterface">
        <wsdl:endpoint name="NewEndpoint" binding="tns:NewBinding"/>
    </wsdl:service>
</wsdl:description>



This is the same service in WSDL 1.1 - notice the verbosity compared to 2.0:

service has binding, binding has porttype, porttype has operations, operation has message... what a mess!

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://new.webservice.namespace" targetNamespace="http://new.webservice.namespace">
    <wsdl:types>
        <xs:schema targetNamespace="http://new.webservice.namespace" elementFormDefault="qualified"/>
    </wsdl:types>
    <wsdl:message name="NewMessageRequest">
        <wsdl:part name="parameter" type="xs:string"/>
    </wsdl:message>
    <wsdl:message name="NewMessageResponse">
        <wsdl:part name="parameter" type="xs:string"/>
    </wsdl:message>
    <wsdl:portType name="NewPortType">
        <wsdl:operation name="NewOperation">
            <wsdl:input message="tns:NewMessageRequest"/>
            <wsdl:output message="tns:NewMessageResponse"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="NewBinding" type="tns:NewPortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="NewOperation">
            <soap:operation soapAction="urn:#NewOperation"/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="NewService">
        <wsdl:port name="NewPort" binding="tns:NewBinding">
            <soap:address location="No Target Adress"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>




I hate WSDL, and the whole XML paraphernalia created to implement distributed computing around the XML paradigm.
I am trying to understand why I hate this entire technology.
Being a Java developer, I like the extreme coherence of Data and Interfaces definitions implemented in Java:
if you break something, you will immediately notice at design time.
With XML and WSDL, you always have the impression of handling a wobbly jellyfish, overly complex and redundant, leaving open holes for ambiguity and crappy implementations.
In fact, in my own experience AXIS2, SOAPUI and Clientgen operate differently, a WSDL which works with the first 2 doesn't work in Clientgen.... CRAP!

http://en.wikipedia.org/wiki/Web_Services_Description_Language

In a WSDL you have DEFINITIONS of public services.

NAMESPACES are used to make names less ambiguous, and should regarded as packages. Their syntax in reality is obscure and ambiguous.

SERVICES are exposed in the service URL; http://host:port/WEB_CONTEXT_ROOT/service


A SERVICE is associated to a BINDING, which defines the protocol (SOAP) and the way to pass arguments (DOCUMENT).



in the BINDING you MAY redefine OPERATIONS, but they are already defined in the PORT TYPE.
OPERATIONS are associated at times with SOAP ACTION.

A PORT TYPE is a misnomer, in WSDL 2.0 it is called INTERFACE, which is what it actually is. It defines OPERATIONS (=method) and their MESSAGES (=parameters).

In TYPES there is the type definition of method parameters.


So all in all you have a very complex and articulated document to do very simple stuff:
defining ENDPOINTS, PROTOCOL, PUBLIC INTERFACES, DATA TYPES
Why all this could not be done in a simpler way....finally leaving the developer to rely on automated tools.... EJB 2.0 reloaded.... we already know that it will all end up in a EJB 3.0 where AT LAST the good stuff is done.... so why not do it since the beginning...


Let's look in Wikipedia the changes made in WSDL 2.0:

- Removal of message constructs
EXACTLY! There should be only OPERATIONS. MESSAGES are useless indirection.

- PortTypes renamed to interfaces
PortTypes are simply a list of Operations... so... call it Interface, no?

- Ports renamed to endpoints.
In fact it simply defines a URL for the Service

Furthermore, some definitions - like endpoint - have been inlined in WSDL 2.0, making the document more compact and readable.

WSDL 2.0 is barely tolerable, WDSL 1.0 is simply outrageous, my grand mother could have done a better job.



UNFORTUNATELY OSB 3.0 doesn't seem to recognize this WSDL 2.0 format, when I try to import the WSLD it complains about:

An error occurred creating the resource:
org.apache.xmlbeans.XmlException: error: The document is not a definitions@http://schemas.xmlsoap.org/wsdl/: document element mismatch got description@http://www.w3.org/ns/wsdl


Monday, February 15, 2010

WSDL import and XSD import

http://www.ibm.com/developerworks/xml/library/ws-tip-imports.html

an interesting article on the mysteries of WSDLs... its conclusions are:
  • It is a good practice to use XSD imports to import schema, and to use WSDL imports to import WSDL.
  • It is a good practice to import all of the namespaces that you use.
  • An attribute value of the import namespace must match the imported targetNamespace value.
  • The primary purpose of an import statement is to import namespaces. The schemaLocation and location attributes, though sometimes necessary, are really only hints.