Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Handling Web Services with Apache AXIS Web-Service Review By Examples ... POST /wsprimegenerator.exe/soap/IPrimeGenerator HTTP/1.0 Content-Type: text/xml; charset=utf-8 Host: www.jusufdarmawan.com SOAPAction: "urn:UnitIPrimeGenerator-IPrimeGenerator#primegenerator" Content-Length: 527 A request to <?xml version="1.0" encoding="UTF-8"?> www.jusufdarmawan.com <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:primegenerator soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:UnitIPrimeGenerator-IPrimeGenerator"> <valstart xsi:type="xsd:string">12</valstart> <valend xsi:type="xsd:string">120</valend> </ns1:primegenerator> </soapenv:Body> </soapenv:Envelope> HTTP/1.0 200 OK Date: Mon, 09 May 2005 20:58:35 GMT Content-Length: 619 Content-Type: text/xml Server: Microsoft-IIS/5.0 X-Powered-By: ASP.NET <?xml version="1.0" encoding='UTF-8'?> The Response <SOAP-ENV:Envelope xmlns:SOAP- ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <NS1:primegeneratorResponse xmlns:NS1="urn:UnitIPrimeGenerator-IPrimeGenerator" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="xsd:string">13,17,19,23,29,31, 37, 41,43, 47, 53,59,61,67,71,73,79,83,89,97,101,103,107,109,113</return> </NS1:primegeneratorResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> POST /soap HTTP/1.0 SOAPAction: "" Content-Length: 520 A request to services.xmethods.net <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:getRate soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:xmethods-CurrencyExchange"> <country1 xsi:type="xsd:string">Euro</country1> <country2 xsi:type="xsd:string">Israel</country2> </ns1:getRate> </soapenv:Body> </soapenv:Envelope> HTTP/1.0 200 OK Date: Sat, 07 May 2005 23:26:21 GMT Content-Length: 492 The Response Content-Type: text/xml <?xml version='1.0' encoding='UTF-8'?> <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'> <soap:Body> <n:getRateResponse xmlns:n='urn:xmethods-CurrencyExchange'> <Result xsi:type='xsd:float'>5.5825</Result> </n:getRateResponse> </soap:Body> </soap:Envelope> <?xml version="1.0"?> <definitions name="CurrencyExchangeService" A WSDL Example targetNamespace="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl" xmlns:tns="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="getRateRequest"> <part name="country1" type="xsd:string"/> <part name="country2" type="xsd:string"/> </message> <message name="getRateResponse"> <part name="Result" type="xsd:float"/> </message> <portType name="CurrencyExchangePortType"> <operation name="getRate"> <input message="tns:getRateRequest" name="getRate"/> <output message="tns:getRateResponse" name="getRateResponse"/> </operation></portType> <binding name="CurrencyExchangeBinding" type="tns:CurrencyExchangePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getRate"> <soap:operation soapAction=""/> <input name="getRate"> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output name="getRateResponse"> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="CurrencyExchangeService"> <documentation>Returns the exchange rate between the two currencies</documentation> <port name="CurrencyExchangePort" binding="tns:CurrencyExchangeBinding"> <soap:address location="http://services.xmethods.net:80/soap"/> </port> </service> </definitions> WSDL Elements Service * Port Binding Input Output Operation * Port Type Apache EXtensible Interaction System (Axis) What is AXIS • Axis is essentially a SOAP engine – a framework for constructing SOAP processors - client side - server side • Axis implements the interfaces of JAX-RPC (XML-based remote procedure calls in Java) • AXIS = Apache EXtensible Interaction System Apache AXIS: Included Tools • A simple stand-alone server • A Web application that resides in Servlet engines, such as Tomcat • Standalone tools for Web-service invocation - Java/C components • Extensive support for the Web Service Description Language (WSDL) - E.g., tools for generating Java classes (stubs) from WSDL and vice versa • … and more Remote Method Invocation is not New • java.rmi has been in Java since Java’s early versions • In Java RMI, objects can invoke methods of objects that reside on a remote computer - (RMI = Remote Method Invocation) • So, what has been changed? - Using HTTP for communication - Using agreed protocols, Java can invoke methods that were not written in Java (e.g., .NET methods) and vice versa - A complex registry procedure has been required in RMI What We Would Like to Create • Client applications: applications that can call a remote Web service • Services: methods that can be called by remote applications • Service descriptions: WSDL files that describe our methods Client Applications Calling Web Services • By now, we already know how to invoke a remote Web service in Java: - Open a socket to the remote server - Through the socket, send a SOAP request wrapped by a HTTP request - Parse the response (e.g., using SAX/DOM) • However, this approach is cumbersome, and most of it can be automated - This is the whole point of using standards… Invoking Services with Apache • Axis includes comfortable tools for managing calls to Web services • The programmer configures the request for the Web service using a friendly API - with, or without considering the WSDL • According to the configuration, a method invocation is transformed into a SOAP request that is sent to the remote server Invoking Services with Axis • To invoke an operation of a Web service, do the following: - Construct a Service instance - Using the Service instance, generate a Call instance - Configure the Call instance - Invoke the call Example: Currency Exchange import org.apache.axis.client.*; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import javax.xml.rpc.encoding.XMLType; public class CurrencyExchange { public static void main(String[] args) throws Exception { System.setProperty("http.proxyHost","wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); String endpointUrl = "http://services.xmethods.net:80/soap"; String nsuri = "urn:xmethods-CurrencyExchange"; Service service = new Service(); Call call = (Call) service.createCall(); Example: Currency Exchange (cont) call.setTargetEndpointAddress(endpointUrl); call.setOperationName(new QName(nsuri,"getRate")); call.addParameter("country1", XMLType.SOAP_STRING, ParameterMode.IN); call.addParameter("country2", XMLType.SOAP_STRING, ParameterMode.IN); call.setReturnType(XMLType.SOAP_FLOAT); Object ret = call.invoke(new Object[] {"Euro","Israel"}); System.out.println(ret); } } Using the WSDL • Axis can read a given WSDL and configure the service as much as possible from that WSDL • Instead of using the default constructor, construct the service using the following constructor: Service(String wsdlLocation, QName serviceName) • When there is only one port, we can obtain it automatically • In this approach, you usually need to know the following about the service: - the WSDL URL, the service name, the namespace uri, the operation name and the expected arguments public class CurrencyExchange2 { public static void main(String[] args) throws Exception { System.setProperty("http.proxyHost",“wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); String wsdl = "http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl"; QName sName = new QName("http://www.xmethods.net/sd/CurrencyExchangeService.wsdl", "CurrencyExchangeService"); String oName = "getRate"; Service service = new Service(wsdl, sName); QName port = (QName)service.getPorts().next(); Call call = (Call)service.createCall(port, oName); System.out.println(call.invoke(new Object[] {"UK","Israel"})); }} public class PrimeNumbers { public static void main(String[] args) throws Exception { System.setProperty("http.proxyHost",“wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); String wsdl = "http://www50.brinkster.com/vbfacileinpt/np.asmx?wsdl"; QName sName = new QName("http://www50.brinkster.com/vbfacileinpt/np","pnum"); String oName = "GetPrimeNumbers"; Service service = new Service(wsdl, sName); QName port = (QName)service.getPorts().next(); Call call = (Call)service.createCall(port, oName); System.out.println(call.invoke(new Object[] {100})); }} The WSDL2Java Application • Axis provides a mechanism for communicating with a Web service using stubs • That is, generation of regular Java classes that have an interface similar to that of the Web service and implementation that wraps Web service management • Invoke class WSDL2Java in order to create the required Java classes Generated Classes • WSDL2Java generates the following: - A service interface and a service implementation (locator) for each service - A stub class for each binding - An interface for each port type • This interface contains methods that correspond to the operations of the port type - A class for each complex type An Example Using The Generated Classes import com.brinkster.www50.vbfacileinpt.np.*; public class PrimeNumbers2 { public static void main(String[] args) throws Exception { System.setProperty("http.proxyHost","wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); PnumSoap ps = new PnumLocator().getpnumSoap(); System.out.println(ps.getPrimeNumbers("20")); } } Server Applications AXIS Installation • Axis works inside a Servlet container (e.g., Tomcat) • You should add to your Tomcat libs some jar files: axis.jar, saaj.jar, wsdl4j.jar, … • You need to include several jar files in your CLASSPATH • This has already been done for you! - The needed CLASSPATH definitions where added to dbi.cshrc - The needed jar files are in $CATALINA_HOME/lib/ AXIS Installation (cont) • You need to copy the Axis application to your Tomcat's application directory: cp -r ~dbi/tomcat/axis/ $CATALINA_BASE/webapps $CATALINA_BASE $CATALINA_HOME webapps lib myapplication axis The directory that you need to copy axis.jar saaj.jar Classes were added for you … Creating a Web Service Next, we will see how we can create and publish a Web service using the Axis plugin in Tomcat 1. Generate the Implementing Class package myws; public class Power { public int power(int a, int n) { return (int)Math.pow(a,n); } } $CATALINA_BASE/webapps/axis/WEB-INF/ classes/myws/Power.class 2. Deploy the Service using Web Service Deployment Descriptor <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="mypower" provider="java:RPC"> <parameter name="className" value="myws.Power"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> services.wsdd java org.apache.axis.client.AdminClient -hlocalhost -p8080 services.wsdd That's it! You Can Call the Service. import org.apache.axis.client.*; public class PowerClient { public static void main(String[] argv)throws Exception { String endpoint = "http://mangal:8080/axis/services/mypower"; Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("power"); Object value = call.invoke(new Object[] {new Integer(2), new Integer(5)}); System.out.println(2+"^"+5 +"=" + value); } } How Does it Work? • The AXIS plugin is simply a Web application that resides in Tomcat (under webapps/) • The Servlet AxisServlet of this application is responsible for invoking services • All URLs of the form /services/* are mapped to the AxisServlet - Where is that written? How Does it Work? (cont) • The wsdd file defines mappings between a Web service elements to a Java class elements - I.e., names, methods, etc. • The class AdminClient sends a request to the application to register the service based on the wsdd content • When a SOAP request arrives, the AxisServlet object parses the request and invokes the corresponding method of the class associated with the service URL The Deployment Descriptor <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="mypower" provider="java:RPC"> <parameter name="className" value="myws.Power"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> services.wsdd The Scope of the Object • Request (the default): a new object is created for each request, the service instance is available for the duration of the request (regardless of forwarding) • Session: a new object is created for each new session and the service instance is available for the entire session • Application: a singleton shared service instance is used to serve all invocations Undeploying a Service <undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="mypower"/> undeploy.wsdd </undeployment> java org.apache.axis.client.AdminClient -hlocalhost -p8080 undeploy.wsdd Implementing Classes • The class that implements the Web service must be accessible to the Axis Servlet • Hence, this class should reside in a package in $CATALINA_BASE/webapps/axis/WEB-INF/classes/ • Of course, all helper classes should be accessible to the Axis application too The Service WSDL • Axis automatically provides a WSDL for each deployed service • To get the WSDL, use the service URL with the empty argument wsdl http://localhost:8080/axis/services/mypower?wsdl Power-Service WSDL <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://inferno-02/axis/services/mypower" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost/axis/services/mypower" xmlns:intf="http://localhost/axis/services/mypower" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:message name="powerResponse"> <wsdl:part name="powerReturn" type="xsd:int"/> </wsdl:message> <wsdl:message name="powerRequest"> <wsdl:part name="a" type="xsd:int"/> <wsdl:part name="n" type="xsd:int"/> </wsdl:message> <wsdl:portType name="Power"> <wsdl:operation name="power" parameterOrder="a n"> <wsdl:input message="impl:powerRequest" name="powerRequest"/> <wsdl:output message="impl:powerResponse" name="powerResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="mypowerSoapBinding" type="impl:Power"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="power"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="powerRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://myws" use="encoded"/> </wsdl:input> <wsdl:output name="powerResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/axis/services/mypower" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="PowerService"> <wsdl:port binding="impl:mypowerSoapBinding" name="mypower"> <wsdlsoap:address location="http://inferno-02:8080/axis/services/mypower"/> </wsdl:port> </wsdl:service> </wsdl:definitions> jws Files • There is a fast and easy way of crating a service: 1. Create a Java class myClass.java 2. Rename your class to end with jws: myClass.jws 3. Put the jws file directly under the directory $CATALINA_BASE/webapps/axis/ (the application’s root) 4. That is all. Now you can call the service! Example: a Calculator Service public class SimpleCalculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } } $CATALINA_BASE/webapps/axis/SimpleCalculator.jws Service URL: http://server:port/axis/SimpleCalculator.jws Example: a Calculator Service public class CalculatorClient { public static void main(String[] argv)throws Exception { String endpoint = "http://localhost:8080/axis/SimpleCalculator.jws"; Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("add"); Object value = call.invoke(new Object[] {new Integer(4), new Integer(6)}); System.out.println(value); } } How does it Work? • On the first time the jws file is being called, it is compiled into a class - WEB-INF/jwsClasses/SimpleCalculator.class • Axis then considers the URL of the jws as one of a regular web service - Default configurations are assumed • Sounds like any other technology we know? When not to Use jws Files • • • • When you do not have the Java source code When you don’t want to expose your code When you want to use custom type mappings When you want to use other configuration options Axis Type Mappings Axis Type Mappings • Axis uses mappings between SOAP types and Java classes and primitive types • Serialization and deserialization are executed by objects of the interfaces Serializer and Deserializer (provided by Axis), respectively - For example, SimpleSerializer, SimpleDeserializer, DateDeserializer, ArraySerializer Axis Type Mapping Complex Type Example - Service Side package myws; import java.util.*; public class VectorService { public Vector getAsVector(int[] array) { Vector result = new Vector(); for(int i=0; i<array.length; ++i) result.add("Number " + array[i]); return result; } } VectorService.java <service name="tovector" provider="java:RPC"> <parameter name="className" value="myws.VectorService"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="getAsVector"/> </service> services.wsdd Input in The WSDL <complexType name="ArrayOf_xsd_int"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[]"/> </restriction> </complexContent> </complexType> <wsdl:message name="getAsVectorRequest"> <wsdl:part name="array" type="impl:ArrayOf_xsd_int"/> </wsdl:message> Output in The WSDL <complexType name="Vector"> <sequence> <element maxOccurs="unbounded" minOccurs="0" name="item" type="xsd:anyType"/> </sequence> </complexType> <wsdl:message name="getAsVectorResponse" <wsdl:part name="getAsVectorReturn" type="apachesoap:Vector"/> </wsdl:message> Complex Type Example - Client Side import java.util.*; import org.apache.axis.client.*; public class VectorClient { public static void main(String[] argv)throws Exception { String endpoint = "http://localhost:7000/axis/services/tovector"; Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("getAsVector"); int[] array = {3,7}; Vector value = (Vector)call.invoke(new Object[] {array}); printVector(value); } VectorClient.java A Snapshot from the Request <getAsVector soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <arg0 xsi:type="soapenc:Array" soapenc:arrayType="xsd:int[2]" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <item>3</item> <item>7</item> </arg0> </getAsVector> A Snapshot from the Response <getAsVectorResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getAsVectorReturn href="#id0"/> </getAsVectorResponse> <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns1:Vector" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://xml.apache.org/xml-soap"> <item xsi:type="soapenc:string">Number 3</item> <item xsi:type="soapenc:string">Number 7</item> </multiRef> Java Beans • Java Beans are simply objects of classes that follow some (natural) coding conventions: - An empty constructor - A readable property has a matching getter - A writable property has a matching setter • A property has name and a type • The getter of property prop: type getProp() • The setter of property prop: void setProp(type) An Example package myws; public class Person { private String firstName, lastName; private int personID; property firstName public String getFirstName() {return firstName;} public void setFirstName(String firstName) { this.firstName = firstName;} public String getLastName() {return lastName;} public void setLastName(String lastName) { this.lastName = lastName; Property lastName } public void setId(int id) {personID = id;} public int getId(int id) {return personID;} } Property id Using Beans in Web Services • A Web service can use beans in its definition - either in its input or output • For that, you need to tell the Axis engine that the corresponding object needs to be serialized as a bean • In this serialization, every accessible property (i.e., one that has a getter/setter) is specified • Where, in the file system, should the bean class reside? A Service Example package myws; public class PersonService { public Person createPerson() { Person person = new Person(); person.setFirstName("f"); person.setLastName("l"); person.setId(2); return person; } } The WSDD <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="person" provider="java:RPC"> <parameter name="className" value="myws.PersonService"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="*"/> <beanMapping qname="ns:person" xmlns:ns="http://www.cs.huji.ac.il/~dbi/xsd" languageSpecificType="java:myws.Person"/> </service> </deployment> Using Beans in Clients • To use a bean on the client side, you need to configure service to deserialize the SOAP type into a Java bean • For that, we use the class BeanDeserializer provided by Axis • Note that client and server beans need not be the same class - What should they have in common? public class PersonClient { public static void main(String[] argv) throws Exception { String endpoint = "http://localhost/axis/services/person"; Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("createPerson"); QName qn = Identical to new QName("http://www.cs.huji.ac.il/~dbi/xsd", "person"); Person BeanDeserializerFactory bdf = new BeanDeserializerFactory(MyPerson.class,qn); call.registerTypeMapping(MyPerson.class, qn, null, bdf); MyPerson value = (MyPerson)call.invoke(new Object[] {}); System.out.println(value); } } Exception Handling Exception in Service Calls • Several problems can cause exception to be thrown when a service is being invoked • For example - the server cannot be connected - the server does not find the requested URL - the request is inappropriate (no such operation, invalid arguments, etc.) - the implementing service method has thrown an exception Service Exception • When the implementing service throws an exception, a SOAP fault response is returned by the server • The client invocation method translates this response to a java.rmi.RemoteException after parsing the response An Example package myws; public class ExceptionService { public void throwException() throws IllegalStateException { throw new IllegalStateException ("I only throw an exception!"); }} <service name="exception" provider="java:RPC"> <parameter name="className" value="myws.ExceptionService"/> <parameter name="allowedMethods" value="*"/> </service> services.wsdd public class ExceptionClient { public static void main(String[] argv){ String endpoint = "http://localhost:80/axis/services/exception"; try { Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("throwException"); Object value = call.invoke(new Object[] {}); System.out.println(value); } catch(RemoteException exp) { System.err.println("WS invocation error: " + exp.getMessage()); } catch(Exception exp) { System.err.println("Error: " + exp.getMessage());}}} A Snapshot from the Response <soapenv:Body> <soapenv:Fault> <faultcode>soapenv:Server.userException</faultcode> <faultstring>java.lang.IllegalStateException: I only throw an exception!</faultstring> <detail>...</detail> </soapenv:Fault> </soapenv:Body>