@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)
No comments:
Post a Comment