How do I know the WSDL URL of my Web Service ?

In this tutorial we will learn how to retrieve the SOAP Web Service WSDL URL, so that you can quickly test your SOAP Web Service.

Ok let’s begin from the following SOAP Web Service application available on JBoss EAP or WildFly. Here is the server log upon deployment:

16:18:12,387 INFO  [org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean] (MSC service thread 1-6) Creating Service {http://www.jboss.org/jbossws/ws-extensions/wsaddressing}AddressingService from WSDL: WEB-INF/wsdl/AddressingService.wsdl
16:18:12,788 INFO  [org.apache.cxf.endpoint.ServerImpl] (MSC service thread 1-6) Setting the server’s publish address to be http://localhost:8080/wildfly-jaxws-addressing/AddressingService
16:18:12,873 INFO  [org.jboss.ws.cxf.deployment] (MSC service thread 1-6) JBWS024074: WSDL published to: file:/home/francesco/jboss/wildfly-10.0.0.Final/standalone/data/wsdl/wildfly-jaxws-addressing-service.war/AddressingService.wsdl

This information informs us about the published address of the SOAP Web Service which is set to : http://localhost:8080/wildfly-jaxws-addressing/AddressingService?wsdl

Besides server logs, there are other strategies to retrieve the SOAP Web Service URL:

1) Use the Command Line Interface

By pointing to the deployment unit which contains the SOAP Web Service, it is possible via CLI to retrieve the WSDL URL of it:

[standalone@localhost:9990 /] /deployment=wildfly-jaxws-addressing.war/subsystem=webservices/endpoint=com.demo.AddressingService:read-resource(include-runtime=true) 
{ "outcome" => "success", "result" => 
     { 
       . . . . 
       "wsdl-url" => "http://localhost:8080/wildfly-jaxws-addressing/AddressingService?wsdl" 
     } 
}

 2) Use the Web Admin console

First, connect to the Web Console of the application Server. Next, navigate to the Runtime upper tab of the Web console, and select the Web Services Subsystem:

3) From the WSDL itself (for Top-Down Web Services)

If you are developing Top-Down Web services (also known as Contract-First Web Services), you can define the Contract Definition of your SOAP Web Service in a WSDL file. Within the WSDL, look out for the soad:address location element:

   <service name='ProfileMgmtService'>
      <port binding='tns:ProfileMgmtBinding' name='ProfileMgmtPort'>

         <!-- service address will be rewritten to actual one when WSDL is requested from running server -->
         <soap:address location='http://SERVER:PORT/jaxws-retail/ProfileMgmtBean'/>
      </port>
   </service>

The parameter location contains the WSDL URL for your Web Service. In our case, we rely on the default rewriting of the WSDL address with the actual server address and port, where the service has been deployed.

How is the WSDL URL generated ?

You might however wonder how the WSDL URL is generated. Well the starting point is the SOAP Web Service name, which is defined in the WSDL:

<wsdl:service name="AddressingService">

If you are coding Code-first SOAP Web Service, you can define the Web service name through annotations as follows:

@WebService(
        portName = "AddressingPort",
        serviceName = "AddressingService")
public class AddressingService implements AddressingServiceWs {

//. . .
}

Now you know about the Service name. The host and port where the Service is exposed is a matter of configuration:

In practice, when exposing the SOAP Web Service, the application server performs an URL rewriting of the SOAP Address (contained in the WSDL), replacing the host name with the property wsdl-host and the port with wsdl-port.

Important ! In order for the rewriting to work, set the modify-wsdl-address property to true (By default it’s true). If this property is set to false the <soap:address> URL declared in the WSDL will be used instead.

Customizing the WSDL Path

Since JBossWS-CXF 5.0 it is possible to customize the Path of the WSDL by using a Sed-like syntax replacer. For example:

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
            <modify-wsdl-address>true</modify-wsdl-address>
            <wsdl-path-rewrite-rule>s/regexp/replacement/g</wsdl-path-rewrite-rule>
            <!-- Other configuration -->
</subsystem>

Please notice that, in order to take effect, it is required to set the modify-wsdl-address property to true.

Rewriting the SOAP address using XML descriptors

Finally, you can use the WEB-INF/jboss-webservices.xml file to rewrite the SOAP address, Port or protocol to be exposed by your Web service. Here is an example;

<webservices version="1.2"
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">
  <property>
    <name>wsdl.soapAddress.rewrite.wsdl-host</name>
    <value>hostname</value>
  </property>
  <property>
    <name>wsdl.soapAddress.rewrite.wsdl-port</name>
    <value>8080</value>
  </property>
</webservices>

Web Service Testing

We have created a dedicated tutorial for testing SOAP Web services, which includes:

  • Testing SOAP Web services with SOAPUI
  • Using cURL to test SOAP Web services
  • Testing SOAP Web services with Apache JMeter
  • Programmatically test SOAP Web services with JUnit

You can read it here: How to test SOAP Web Services

How to change the default Web Service deployment Port ?

Web services running on WildFly or JBoss EAP 7 can customize the deployment port of the Web service by setting the wsdl-port or wsdl-secure-port of the webservices subsystem.

Let’s see an example:

/subsystem=webservices:write-attribute(name=wsdl-port,value=8090)

Now deploy a sample Web service and check the Web Service WSDL URL:

/deployment=jaxws-pojo-service.war/subsystem=webservices/endpoint=jaxws-pojo-endpoint%3Aorg.jboss.quickstarts.ws.jaxws.samples.jsr181pojo.JSEBean:read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "average-processing-time" => 0L,
        "class" => "org.jboss.quickstarts.ws.jaxws.samples.jsr181pojo.JSEBean",
        "context" => "jaxws-pojo-endpoint",
        "fault-count" => 0L,
        "max-processing-time" => 0L,
        "min-processing-time" => 0L,
        "name" => "org.jboss.quickstarts.ws.jaxws.samples.jsr181pojo.JSEBean",
        "request-count" => 0L,
        "response-count" => 0L,
        "total-processing-time" => 0L,
        "type" => "JAXWS_JSE",
        "wsdl-url" => "http://localhost:8090/jaxws-pojo-endpoint/JSEBean?wsdl"
    }
}

As you can see, the WSDL URL has been configured to run on Port 8090.

Here is the updated configuration for your reference:

<subsystem xmlns="urn:jboss:domain:webservices:2.0" statistics-enabled="${wildfly.webservices.statistics-enabled:${wildfly.statistics-enabled:false}}">
    <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
    <wsdl-port>8090</wsdl-port>
    <endpoint-config name="Standard-Endpoint-Config"/>
    <endpoint-config name="Recording-Endpoint-Config">
        <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
            <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
        </pre-handler-chain>
    </endpoint-config>
    <client-config name="Standard-Client-Config"/>
</subsystem>

Finally, note that you need to open the WSDL Port in the socket-binding configuration and register it on undertow server.

If you want to run a single HTTP listener in your undertow Web server it is sufficient to change the socket binding of the http listener to “8090” (in our example).

On the other hand, if you want to use multiple HTTP listeners (for example one dedicated to your WSDL Port), we recommend checking this tutorial: How to run multiple HTTP Ports in JBoss / Wildfly

JBoss AS 4 and 5

Basically you need to change port information in 3 configuration files:
At first modify server.xml (With JBoss 4.2.X it’s under deploy/jboss-web.deployer)

    <Connector port=”8080” address=”${jboss.bind.address}”
maxThreads=”250″ maxHttpHeaderSize=”8192″
emptySessionPath=”true” protocol=”HTTP/1.1″
enableLookups=”false” redirectPort=”8443″ acceptCount=”100″
connectionTimeout=”20000″ disableUploadTimeout=”true” />

Next modify jboss-service.xml (under deploy/http-invoker.sar/META-INF/jboss-service.xml )

Modify all attributes named “InvokerURLSuffix” :

<attribute name=”InvokerURLSuffix”>:8080/invoker/EJBInvokerServlet</attribute>
<attribute name=”InvokerURLSuffix”>:8080/invoker/JMXInvokerServlet</attribute>
<attribute name=”InvokerURLSuffix”>:8080/invoker/readonly/JMXInvokerServlet</attribute>
Finally check the jboss-beans.xml (under deploy/jbossws.sar/jbossws.beans/META-INF)

<property name=”webServicePort”>8080</property>

JAX-WS Authentication in a nustshell

In the context of an HTTP transaction, BASIC access authentication is a method for a web browser or other client program to provide a user name and password when making a request.
This tutorial shows how to perform BASIC authentication for JAX-WS Web services. Then, as an alternative, we will learn how to use Apache CXF Interceptors as authentication mechanism.

Continue reading JAX-WS Authentication in a nustshell

What is a Web Service One Way invocation?

Most of the message-exchange-patterns are request-response ones; however in some scenarios
oneway invocations are preferred, as the client does not expect any actual data in the response from
the server.

In such cases, the server is instructed that no SOAP response message has to be sent
back to the client, whose low-level invocation is immediately acknowledged (for instance with a
HTTP 202 response code if the HTTP transport is in use). Moreover the endpoint processing can be
(and usually is) performed in a separate thread, freeing resources that can be used to promptly
serve other requests.
Oneway operations in WSDL documents simply have no {http://schemas.xmlsoap.org/wsdl/}output
elements. On Java code, the @javax.jws.Oneway annotation is used as follows:

@WebService
public class MyServiceEndpoint {
   @Oneway
   public void ping() {
   //
   
   }
}

This Web service expose the method ping as web service and returns the thread of execution before executing the method.

JBoss web services

JAX-WS simplifies the development model for a web service endpoint a great deal. In short, an endpoint implementation bean is annotated with JAX-WS annotations and deployed to the server. The server automatically generates and publishes the abstract contract (i.e. wsdl+schema) for client consumption. All marshalling/unmarshalling is delegated to JAXB.

You can follow two approaches for developing your SOAP web services:

  • Top-down: This approach, also known as contract first, starts with the contract (the WSDL) by defining operations, messages, and so forth. When both the consumer and provider agree on the contract, you can then implement the Java classes based on that contract.
  • Bottom-up: This approach, also known as code first, mandates that the WSDL file has to be generated by the programming interfaces. It is simpler to use for developers that do not have a deep knowledge of the WSDL syntax and it’s the easiest choice if you want to turn your Java classes or EJB into web services.

We will use the code-first approach, that is, we will start by creating a Java class and convert this into a Web service component. The Java class in turn can be either a simple POJO or an EJB component. We will start from a simple POJO class going through the following steps:

  • Create a Service Endpoint Interface (SEI) and define a business method to be used with the web service.
  • Create the implementation class and annotate it as a web service.

Coding the Service Interface

The Service Endpoint Interface is just an abstract interface which outlines the business methods which are available in our Web service.

@WebService
public interface AccountWSItf {
        public void newAccount( String name);

        @WebMethod
        public void withdraw(String name, long amount) throws RuntimeException;

        @WebMethod
        public void deposit(String name, long amount);

        @WebMethod
        public Account findAccountByName(String name);
}

It is noteworthy to observe the @WebService annotation. This annotation is really all it takes to leverage a Web service; when adding this annotation the XML Web Services runtime will generate all the necessary plumbing for transforming a Java method invocation into an XML over HTTP call.

The @WebService annotation also comes with attributes that let you completely define a Web service in terms of contract exposed via the WSDL file. For the moment we will ignore these attributes and proceed with our development.

The other annotation included is javax.jws.WebMethod which is optional and provides the operation name and the action elements that are used to customize the attribute names of the operation in the WSDL document. For the moment, we will rely on the default values of it.

The @WebMethod can be used also to restrict which methods of the Web service are visible to your clients. If it is not included, all Web service methods are available to Web service clients. On the other hand, if any method is annotated with @WebMethod, only those methods will be available.

Our Web service interface references the Account class that is used as persistence layer to store the account attributes:

@Entity
@XmlRootElement
public class Account implements Serializable{

        @Id
        @GeneratedValue
        private Long id;

        String name;
        long amount;

        // Getters/Setters omitted for brevity
}

As you can see, we have added a @XmlRootElement annotation to the Account class. The @XmlRootElement is part of the Java Architecture for XML Binding (JAXB) annotation library. JAXB provides a convenient way to map XML schema to a representation in Java code. In practice, JAXB shields the conversion of XML schema messages in SOAP messages to Java code without having the developers know about XML and SOAP parsing. Therefore, the @XmlRootElement annotation associated with the Account class map the Account class to the XML Root element.

Developing the Implementation class

Having defined our contract, let’s check out the implementation class which is a wrapper to the AccountManager EJB:

@WebService
@SOAPBinding(style= SOAPBinding.Style.RPC)
public class AccountWS implements AccountWSItf{
        @Inject
        AccountManager ejb;

        public void newAccount(@WebParam(name = "name") String name) {
                ejb.createAccount(name);
        }
        public void withdraw(@WebParam(name = "name") String name,
                        @WebParam(name = "amount") long amount) throws RuntimeException {
                ejb.withdraw(name, amount);
        }
        public void deposit(@WebParam(name = "name") String name,
                        @WebParam(name = "amount") long amount) {
                ejb.deposit(name, amount);
        }
       @WebResult(name = "BankAccount")
        public Account findAccountByName(String name) {
                return ejb.findAccount(name);
        }
}

Our service implementation class, named AccountWS, contains a few annotations, which are specific of XML Web Services. The @SOAPBinding annotation included in the class determines how the Web service is bound to the SOAP messaging protocol. There are two programming styles for SOAP binding:

  • RPC: The SOAP message contains the parameters and the return values. The <soap:Body> carries an element with the name of the method or remote procedure being invoked. This element in turn contains an element for each parameter of that procedure.
  • Document-style web service: The SOAP Message has no restrictions on how the SOAP body must be constructed. It allows you to include whatever XML data you want and to include as well a schema for this XML.

Therefore, the Document style is probably more flexible, but the effort for implementing the Web service and clients may be slightly larger.

Besides this, the implementation class contains two annotations: The @javax.jws.WebParam annotation is used to specify the parameter’s name that needs to be exhibited in the WSDL.

You can even define the param type which can be IN, OUT, or INOUT (both) and determines how the parameter is flowing (default is IN).

The other annotation, @javax.jws.WebResult, controls the generated name of the message returned value in the WSDL. By default, the name of the returned value in the WSDL is set to return. By using the @WebResult annotation you can be more specific and have a more expressive contract.

Deploying the Web service

In order to compile and test the example, as usual, you can include the umbrella artifact jakarta.jakartaee-api, otherwise the Web Service dependencies to resolve are the following ones:

<dependency>
    <groupId>org.jboss.spec.javax.xml.ws</groupId>
    <artifactId>jboss-jaxws-api_2.3_spec</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.jws</groupId>
    <artifactId>jsr181-api</artifactId>
    <scope>provided</scope>
</dependency>

Once deployed, your server logs will produce the following output:

Adding service endpoint metadata: id=com.itbuzzpress.jaxws.ws.AccountWS
address=http://localhost:8080/ee-ws-basic/AccountWS
 implementor=com.itbuzzpress.jaxws.ws.AccountWS
 serviceName={http://ws.jaxws.itbuzzpress.com/}AccountWSService
 portName={http://ws.jaxws.itbuzzpress.com/}AccountWSPort
 annotationWsdlLocation=null
 wsdlLocationOverride=null
 mtomEnabled=false
Creating Service {http://ws.jaxws.itbuzzpress.com/}AccountWSService from class com.itbuzzpress.jaxws.ws.AccountWSItf
Setting the server's publish address to be http://localhost:8080/ee-ws-basic/AccountWS

Creating a WS Test client

Once that the Web service is published, you can access the generated WSDL at URL http://localhost:8080/ee-ws-basic/AccountWS?wsdl

From the WSDL file, we can run a simple JUnit test case that executes the three basic use cases (newAccount, deposit, withdraw). So add to your src/test/java folder a class named TestWS, which contains the following:

public class TestWS {
   @Test
   public void testWS() {
   String name ="John Smith";
        try {
       URL url = new URL("http://localhost:8080/ee-ws-basic/AccountWS?wsdl");
                QName qname = new QName("http://ws.jaxws.itbuzzpress.com/",
                                        "AccountWSService");
                Service service = Service.create(url, qname);
                AccountWSItf ws = service.getPort(AccountWSItf.class);
                ws.newAccount(name);
                System.out.println("Created account name " +name);
                ws.deposit(name, 1000);
                System.out.println("Deposit $ 1000 ");
                ws.withdraw(name, 500);
                System.out.println("Withdraw $ 500 ");
                Account account = ws.findAccountByName(name);
                assertNotNull(account);
                long money = account.getAmount();
                assertEquals(500l, money);
                System.out.println("Account balance is " +account.getAmount());                }
       catch (Exception e) {         System.out.println("Exception: "+ e);                 }
   }
}

Within the testWS method, the service.getPort call returns the client proxy to the SOAP

Web service where you can then invoke the methods for creating, depositing and withdrawing money from the account.

The source code for this tutorial is available here:

https://github.com/fmarchioni/practical-enterprise-development/tree/master/code/jaxws/ee-ws-basic

How to test SOAP Web Services

This tutorial will teach how to test SOAP Web Services using open source testing tools or Java testing frameworks.

Coding our SOAP Web Service

Let’s start from the definition of our JAX-WS Web Service contract:

@WebService
public interface AccountWSItf {
	@WebMethod
	public String newAccount( String name);

	@WebMethod
	public String withdraw(String name, long amount) throws RuntimeException;

	@WebMethod
	public String deposit(String name, long amount);

	@WebMethod
	public Account findAccountByName(String name);
}

This is the SOAP Web Service implementation:

@WebService
@SOAPBinding(style= SOAPBinding.Style.RPC)
public class AccountWS implements AccountWSItf{
	@Inject
	AccountManager ejb;

 
	public String newAccount(@WebParam(name = "name") String name) {
		ejb.createAccount(name);
        return "Created Account "+name;
	}

 
	public String withdraw(@WebParam(name = "name") String name,
			@WebParam(name = "amount") long amount) throws RuntimeException {
		ejb.withdraw(name, amount);
		return "withdrawn "+amount;
	}

 
	public String deposit(@WebParam(name = "name") String name,
			@WebParam(name = "amount") long amount) {
		ejb.deposit(name, amount);
		return "deposited "+amount;
	}

	@WebResult(name = "BankAccount")
	public Account findAccountByName(String name) {
		return ejb.findAccount(name);
	}
}

SOAP Web Service Testing with SOAP UI

In order to test a Web Service we need to collect the WSDL URL of the Web service. This tutorial discusses how you can get the URL of a SOAP Web Service on WildFly: How do I know the WSDL URL of my Web Service ?

The recommended option for Web Service Testing is SOAPUI which is available in an OpenSource version and in an Enterprise version called ReadyAPI. You can download SOAPUI from: https://www.soapui.org/downloads/soapui/

Once installed, it’s really simple to perform Web Service testing: select the New Project option from the File menu, which will prompt the following dialog:

Enter the project name and the WSDL address of your SOAP Web service. SOAP UI will import the WSDL and generate a default request for ad-hoc testing and exploring of services:

So for example, to test the “newAccount” action you only have to add the arguments in the SOAP payload:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.jaxws.mastertheboss.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:newAccount>
         <!--Optional:-->
         <arg0>JohnSmith</arg0>
      </ws:newAccount>
   </soapenv:Body>
</soapenv:Envelope>

Then, you can check the Web Service response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:newAccountResponse xmlns:ns2="http://ws.jaxws.mastertheboss.com/">
         <return>Created Account JohnSmith</return>
      </ns2:newAccountResponse>
   </soap:Body>
</soap:Envelope>

SOAP Web Service Testing with cURL

If you want to test your Web Services in a pure and simple bash script, cURL is an handy option. It’s a good idea to have the SOAP XML message generated by SOAPUI, so for example if you saved the above SOAP XML request in a file named “soap.xml”, then you can test the Web Service with cURL as follows:

curl  --header "Content-Type: text/xml;charset=UTF-8"  --data @soap.xml http://localhost:8080/ee-ws-basic/AccountWS

On the other hand, if you don’t have a tool to generate the SOAP XML message to be sent, you can start from a basic template like this one, and specify in it;

  • The NAMESPACE (e.g. “sample.com”)
  • The OPERATION name
  • The list of ARGUMENTS (if any)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://NAMESPACE/">
   <soapenv:Header/>
   <soapenv:Body>
      <sam:OPERATION>          
         <arg0>AAA</arg0>         
      </sam:OPERATION>
   </soapenv:Body>
</soapenv:Envelope>

SOAP Web Service Testing with JMeter

If you are going to run a stress test for your Web Services, then you can use JMeter to build a SOAP Webservice Test Plan. You can download JMeter from https://jmeter.apache.org/download_jmeter.cgi

Launch JMeter and choose from the menu File → Templates… and select template “Building a SOAP Webservice Test Plan”.

Then, click “Create” button. The following Test plan will be created:

Select the HTTP Request and set the server name/port, the Path and the Body Data as you can see from the following picture:

Finally, select the HTTP Header Manager and set the SOAPAction to blank, as we have already specified it in the Body Data payload:

Finally, the Thread Group tells JMeter the number of users you want to simulate, how often the users should send requests, and the how many requests they should send.

You can now run the Test Plan and check the result in the Listener window to visualize the performance of your test.

Testing your SOAP Web Service Programmatically

Finally, let’s check how to test the SOAP Web Service programmatically. We will execute the test using two different strategies:

  • Use the javax.xml.ws.Service class and leveraging our AccountWSItf endpoint interface. With this we can get an implementation of the interface generated dynamically for us that can be used to send compliant SOAP messages to our service.
  • Use the JaxWsProxyFactoryBean from Apache CXF to access and test the Web Service. This requires to add some extra dependencies to test your Web Services however you can enhance the functionality of a JAX-WS endpoint or client proxy, for example by adding interceptors.
public class TestWS {

	@Test
	public void test() {
		 
		String name ="John Smith";
		try {
			URL url = new URL("http://localhost:8080/ee-ws-basic/AccountWS?wsdl");
			QName qname = new QName("http://ws.jaxws.mastertheboss.com/",
					"AccountWSService");

			Service service = Service.create(url, qname);
			AccountWSItf ws = service.getPort(AccountWSItf.class);
			ws.newAccount(name);
			System.out.println("Created account name " +name);
			ws.deposit(name, 1000);
			System.out.println("Deposit $ 1000 ");
			ws.withdraw(name, 500);
			System.out.println("Withdraw $ 500 ");
			Account account = ws.findAccountByName(name);
			assertNotNull(account);

			long money = account.getAmount();
			assertEquals(500l, money);
			System.out.println("Account balance is " +account.getAmount());


		} catch (Exception e) {
			System.out.println("Exception: "+ e);
		}
	}
	@Test
	public void testApacheCXF() {
		String name ="Adam Smith";
		System.out.println("TEST Using Apache CXF native API");

		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setServiceClass(AccountWSItf.class);
		factory.setAddress("http://localhost:8080/ee-ws-basic/AccountWS?wsdl");
		factory.getInInterceptors().add(new LoggingInInterceptor());
		factory.getOutInterceptors().add(new LoggingOutInterceptor());

		AccountWSItf ws = (AccountWSItf) factory.create(); 
		ws.newAccount(name);
		System.out.println("Created account name " +name);
		ws.deposit(name, 1000);
		System.out.println("Deposit $ 1000 ");
		ws.withdraw(name, 500);
		System.out.println("Withdraw $ 500 ");
		Account account = ws.findAccountByName(name);
		assertNotNull(account);
		long money = account.getAmount();
		assertEquals(500l, money);
		System.out.println("Account amount is " +account.getAmount());

	}
}

You can check the full source code of these examples here: https://github.com/fmarchioni/mastertheboss/tree/master/jax-ws/ee-ws-basic

How to debug Web Service request and response

In this tutorial we will see how you can trace your JBoss Web Services applications by using some built-in logging features or using an external TCP dumper.

Using a System Property to Debug SOAP Messages

Debugging SOAP Messages is a critical activity for every application running Web Services. The simplest way to see the full SOAP messages returned by JBoss or WildFly is to add this System Property to your server which will print the incoming and outgoing SOAP XML Messages:
<system-properties>
        <property name="org.apache.cxf.logging.enabled" value="true"/>
</system-properties>

To include this property in the configuration from the CLI:

/system-property=org.apache.cxf.logging.enabled:add(value=true)

Once that this property has been set to true, you will see in your server logs the SOAP Messages. As an example, here is the incoming SOAP Request:

    Address: http://localhost:8090/jaxws-pojo-endpoint/JSEBean
    HttpMethod: POST
    Content-Type: text/xml;charset=UTF-8
    ExchangeId: a6f15ee8-df14-4f1e-9942-36f0475e7bb6
    ServiceName: JSEBeanService
    PortName: JSEBeanPort
    PortTypeName: JSEBean
    Headers: {SOAPAction="", User-Agent=Apache-HttpClient/4.1.1 (java 1.5), connection=Keep-Alive, content-type=text/xml;charset=UTF-8, Host=localhost:8090, Content-Length=287, accept-encoding=gzip,deflate}
    Payload: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:jsr="http://jsr181pojo.samples.jaxws.ws.quickstarts.jboss.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <jsr:echo>
         <arg0>Hello</arg0>
      </jsr:echo>
   </soapenv:Body>
</soapenv:Envelope>

And here is the SOAP Response:

INFO  [org.apache.cxf.services.JSEBean.RESP_OUT] (default task-1) RESP_OUT
    Address: http://localhost:8090/jaxws-pojo-endpoint/JSEBean
    Content-Type: text/xml
    ResponseCode: 200
    ExchangeId: a6f15ee8-df14-4f1e-9942-36f0475e7bb6
    ServiceName: JSEBeanService
    PortName: JSEBeanPort
    PortTypeName: JSEBean
    Headers: {}
    Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:echoResponse xmlns:ns1="http://jsr181pojo.samples.jaxws.ws.quickstarts.jboss.org/"><return>JSEBean pojo: Hello</return></ns1:echoResponse></soap:Body></soap:Envelope>

Adding Logging Feature

Features in CXF works like decorators. It can be applied to server and client bus components. In a nutshell it  extends the functionality of the server, client or the bus. CXF provides some of the built-in Feature implementations and one of them is LoggingFeature feature class. The LoggingFeature class performs logging of SOAP messages. You can simply add the LoggingFeature to your endpoint as follows:

@org.apache.cxf.feature.Features(features={"org.apache.cxf.feature.LoggingFeature"})

Please note that you can add Features using JaxWsServerFactoryBean as shown in the following code:

HelloWorldImpl implementor = new HelloWorldImpl(); 
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); 
svrFactory.setServiceClass(HelloWorld.class); 
svrFactory.setAddress("http://localhost:9000/helloWorld"); 
svrFactory.setServiceBean(implementor); 
svrFactory.getFeatures().add(new LoggingFeature());
svrFactory.create();

Using a Proxy to capture SOAP Messages

Another option is to use a proxy which prints the incoming and outgoing SOAP Messages. There are plenty of options available like netcat, For example, here is how to set up a proxy on port 8082 which forwards tcp messages on port 8080, printing them:

ncat -lkv localhost 8082 -c 'tee /dev/stderr | ncat -v localhost 8080 | tee /dev/stderr'

If you prefer using a graphical tool for setting up a proxy, then you can use Apache TCPMon which is a valuable tool for monitoring your network applications.

Download here the lastest stable release of it.Configuring TCPMon is pretty easy. For our purpose we need to intercept Web Service request before they reach the Server and as well we need to capture response before they reach the client.

In the Admin tab select a Listening port for Apache TCPMon and a target port which corresponds to JBoss AS listening port. For example:


Now modify your Web Services client so that they point to the Apache TCPMon Port instead of JBoss. For example:

 public static void main(String args[]) throws Exception {   
 String endpointURI ="http://127.0.0.1:8888/ejb/HelloWorld?wsdl";   
 String helloWorld = "Hello world!";   
 
 Object retObj = getPort(endpointURI).echo(helloWorld);   
 System.out.println(retObj);   
 }   
In the meantime, you will find the outcomign and incoming SOAP Messages in the TCPMon Console:
TCPMon is a simple and easy to use tool that has many benefits when developing message driven applications. It is particularly useful in developing Web services.
For additional information about it, check:
https://ws.apache.org/tcpmon/tcpmontutorial.html

Expose EJB 3 as Web Services

Starting with Java EE 7, JAX-WS 2.2 is the standard specification for SOAP web services on the Java EE platform. Developing SOAP-based web services using JAX-WS is straightforward and easy. By using annotations, a web service can be written and deployed within minutes. 

Enhancing support for Web services is a driving force introduced since the EJB 2.1 specification. This provides explicit support  for exposing stateless session beans as Web services. Java-based clients may access the Web services through JAX-RPC API, while non-Java clients through SOAP 1.1.

This tutorial provides an example and discusses how can you expose a Stateless Session Bean as a Webservice endpoint. Also we’ll analyze what are the pros and cons of this approach.

What’s the advantage of exposing an EJB as Web service instead of exposing a POJO as Web services ? 

At first, the EJB option offers a richer set of protocols for your web services: you can access your services
through SOAP and RMI (simply adding a remote interface).
Second, since the EJB are running in an EJB container, you have access to framework like declarative security and transactions. You can even add another layer using interceptors to your EJB.

The following Table compares EJB Web Services with POJO Web Services:

FeatureEJB Web ServicePOJO Web Service
POJOYesYes
Dependency InjectionYesYes
Life cycle methodsYesYes
Declarative transactionsYesNo
Declarative securityYesNo

Here’s a stateless Session bean with a method getUserInfo which returns an object Person

package com.sample;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
@Stateless @WebService public class SampleWS implements SampleWSLocal {     public SampleWS() {     }     @WebMethod     public Person getPerson(@WebParam(name = "userId")             String userId) {         return new Person("michael","jackson");         } }

The only method exposed is getPerson which returns an instance of a simple POJO, Person. When you declare you Session Bean as WebService it means that the Container takes care to generate all the required stubs and the WSDL which describes the Contract between your Web Service and its Consumers.

Notice here: the @WebService annotation is on the Bean class method. If you use the @WebService annotation on the interface, then all public methods on the web service endpoint will be exposed in the web service.

In this sample we return a Person object: how can we return Java Objects to non-java clients ? the answer is that all objects sent via SOAP are serialized into XML. Here’s our SOAP response message serialized:

<ns2:getPersonResponse xmlns:ns2="http://neptune/tasklist" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <return>
    <name>michael</name>
    <surname>jackson</surname>
  </return>
</ns2:getPersonResponse>

Exception Handling in EJB Web Services

When an error occurs while running a Web Service implemented as an EJB, the EJB should throw an exception. When an exception is thrown, the Web Services Servlet returns a Web Services (SOAP) fault. 

Best practices for EJB Web Services

Beware of returning large Object graph to the client: the XML representation of data can be quite big making up huge SOAP messages. In such  situation it’s preferred to return simple Integer for example.

Another best practice is to expose only Coarse Grained EJB methods. What are Coarse Grained EJB methods ? Let’s make an example: You want to represent an order system with an EJB. You can split each order line its own EJB (fine grained), or you can have one EJB arranging the entire order (coarse grained).
In our scenario it’s better to expose EJB as Coarse grained so that you have fewer SOAP-EJB calls,less network load, and fewer transaction context.

Is it possible to expose Stateful session beans as well ? the answer is no because a Stateful Session Bean  cannot have a Web Service Endpoint Interface (SEI). This is because SOAP based Web Services are inherently stateless in nature.

Top-down Web services or Bottom-up ?

This approach for creating Web services is called bottom-up development. As a matter of fact Web Services can be created using two methods: top-down development and bottom-up development. Bottom-up Web services development involves creating a Web service from a Java„¢ bean or enterprise bean.
Top-down Web services are created from a Contract, stated by the WSDL, and next represented by a Class.

Which approach is better ? SOA analyst consider Top-Down development as the pure approach because the nature of the Web services is driven directly by the business and at last engineered in an Object. On the other hand bottom-up Web service development may be faster and easier, especially if you are new to Web services.

My personal opinion is that Top-Down approach might be the right choice for start-up projects, assumed that you have the necessary skills. While bottom-up Web services could be the solution for exposing your EJB layer as Web services, assuming that this layer has already been consolidated.

JAX-WS asynchronous Web Services made simple

Developing rigorous and responsive web service client applications has always been a challenge for architects and developers. JAX-WS 2.0 comes with one effective solution to this problem: asynchronous web service invocation. In this article, we will provide an exposition of this technology with examples built upon the reference implementation.

The JAX-WS programming model offers two models for invoking operations asynchronously – polling and callback. Both methods allow the client to continue processing while waiting for a response.

Let’s see an example taken from the JAX-WS suite of examples:

package org.jboss.test.ws.jaxws.samples.asynchronous;

import java.util.concurrent.Future;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;

@WebService(name = "Endpoint", targetNamespace = "http://org.jboss.ws/jaxws/asynchronous") @SOAPBinding(style = Style.RPC) 

public interface Endpoint {
  @WebMethod(operationName = "echo") 
  public Response echoAsync(@WebParam(name = "String_1") String string1);

  @WebMethod(operationName = "echo") 
  public Future echoAsync(@WebParam(name = "String_1") String string1, @WebParam(name = "asyncHandler") AsyncHandler asyncHandler);
  
  @WebMethod @WebResult(name = "result") 
  public String echo(@WebParam(name = "String_1") String string1);
}

And this is the Service Implementation class:

package org.jboss.test.ws.jaxws.samples.asynchronous;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import org.jboss.logging.Logger;

@WebService(name = "Endpoint", targetNamespace = "http://org.jboss.ws/jaxws/asynchronous") @SOAPBinding(style = Style.RPC) public class EndpointBean {
  private static Logger log = Logger.getLogger(EndpointBean.class);

  @WebMethod @WebResult(name = "result") 
  public String echo(@WebParam(name = "String_1") String msg) {
    log.info("echo: " + msg);
    return msg;
  }
}

As you can see the SEI has two methods echoAsynch each one is implementing a different strategy:

public Response<String> echoAsync(@WebParam(name = "String_1") String string1);

This will use a polling or “pull strategy”. Once the initial request is made the client is free to pursue other work until the request completes. This enables the client to execute other tasks that don’t depend on the outcome of the request. Once the request completes, the response is made available to the client.

On the other hand, using this method:

public Future<?> echoAsync(@WebParam(name = "String_1") String string1, @WebParam(name = "asyncHandler") AsyncHandler<String> asyncHandler);

The actual response is processed by the specified AsyncHandler implementation. Once the response is made available to the callback handler, the code flow is much the same as with polling client.

Callback calls process the response on a different thread from the one the client is running on. This allows the client to gain some control over performance if there are many concurrent asynchronous requests.

Tip: Asynchronous polling clients are especially useful for implementing Web services based work flows. Asynchronous callback clients are helpful when implementing batch processing and notification consumer applications

The web service client

One can implement a JAX-WS asynchronous client using two strategy: one high level which hide the details of the invocation (Dynamic Proxy) and a low level Api called Dispatch.

Web Service client with Dynamic Proxy

We’ll examine at first the Dynamic Proxy approach: the dynamic proxy is the high level API to access web services, here you create an instance of a client proxy using one of getPort methods on the Service:

package org.jboss.test.ws.jaxws.samples.asynchronous;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.xml.namespace.QName;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
import javax.xml.ws.Service;
import junit.framework.Test;
import org.jboss.wsf.test.JBossWSTest;
import org.jboss.wsf.test.JBossWSTestSetup;
public class AsynchronousProxyTestCase extends JBossWSTest {
  private String targetNS = "http://org.jboss.ws/jaxws/asynchronous";
  private Exception handlerException;
  private boolean asyncHandlerCalled;
  public static Test suite() {
    return new JBossWSTestSetup(AsynchronousProxyTestCase.class, "jaxws-samples-asynchronous.war");
  }
  public void testInvokeAsync() throws Exception {
    Endpoint port = createProxy();
    Response response = port.echoAsync("Async");
    // access future 
    String retStr = (String) response.get();
    assertEquals("Async", retStr);
  }
  public void testInvokeAsyncHandler() throws Exception {
    AsyncHandler handler = new AsyncHandler() {
      public void handleResponse(Response response) {
        try {
          String retStr = (String) response.get(1000, TimeUnit.MILLISECONDS);
          assertEquals("Hello", retStr);
          asyncHandlerCalled = true;
        } catch (Exception ex) {
          handlerException = ex;
        }
      }
    };
    Endpoint port = createProxy();
    Future future = port.echoAsync("Hello", handler);
    future.get(1000, TimeUnit.MILLISECONDS);
    if (handlerException != null) throw handlerException;
    assertTrue("Async handler called", asyncHandlerCalled);
  }
  private Endpoint createProxy() throws MalformedURLException {
    URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
    QName serviceName = new QName(targetNS, "EndpointBeanService");
    Service service = Service.create(wsdlURL, serviceName);
    return (Endpoint) service.getPort(Endpoint.class);
  }
}

As this class extends JBossWS test suite, it will implement a “suite” method used to setup and deploy your web service on JBoss:

 public static Test suite()
   {
     return
      new JBossWSTestSetup(AsynchronousProxyTestCase.class, "jaxws-samples-asynchronous.war");
   }

The client has 2 test method each one use a different approach to retrieve the data: the first testInvokeAsync uses the pull strategy :

public void testInvokeAsync() throws Exception {
 
  Endpoint port = createProxy();
      Response response = port.echoAsync("Async");     
      String retStr = (String) response.get();
      assertEquals("Async", retStr);
}

Here asynchronous operation invocations are decoupled from the BindingProvider instance at invocation time such that the response context is not updated when the operation completes. Instead a separate response context is made available using the Response interface.

And the other testInvokeAsyncHandler employs a callback mechanism to handle process invocation result.

 public void testInvokeAsyncHandler() throws Exception
   {
      AsyncHandler<String> handler = new AsyncHandler<String>()
      {
         public void handleResponse(Response response)
         {
            try
            {
               String retStr = (String) response.get(1000, TimeUnit.MILLISECONDS);
               assertEquals("Hello", retStr);
               asyncHandlerCalled = true;
            }
            catch (Exception ex)
            {
               handlerException = ex;
            }
         }
      };   
      Endpoint port = createProxy();
      Future future = port.echoAsync("Hello", handler);
 ....
}

Web Service client with Dispatcher

The higher level JAX-WS APIs are designed to hide the details of converting between Java method invocations and the corresponding XML messages, but in some cases operating at the XML message level is desirable.
Dispatch is a low level API that requires clients to construct messages or message payloads as XML and requires an intimate knowledge of the desired message or payload structure. We use this class in order to support input and output of messages or message payloads of any type.

package org.jboss.test.ws.jaxws.samples.asynchronous;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Response;
import javax.xml.ws.Service;
import javax.xml.ws.Service.Mode;
import junit.framework.Test;
import org.jboss.wsf.test.JBossWSTest;
import org.jboss.wsf.test.JBossWSTestSetup;
import org.jboss.wsf.common.DOMUtils;
import org.jboss.wsf.common.DOMWriter;
import org.w3c.dom.Element;
public class AsynchronousDispatchTestCase extends JBossWSTest {
  private String targetNS = "http://org.jboss.ws/jaxws/asynchronous";
  private String reqPayload = "<ns2:echo xmlns:ns2="
  " + targetNS + "
  "><string_1></string_1>Hello</ns2:echo>";
  private String expPayload = "<ns2:echoresponse xmlns:ns2="
  " + targetNS + "
  "><result></result>Hello</ns2:echoresponse>";
  private Exception handlerException;
  private boolean asyncHandlerCalled;
  public static Test suite() {
    return new JBossWSTestSetup(AsynchronousDispatchTestCase.class, "jaxws-samples-asynchronous.war");
  }
  public void testInvokeAsynch() throws Exception {
    System.out.println("testInvokeAsynch");
    Source reqObj = new StreamSource(new StringReader(reqPayload));
    Response response = createDispatch().invokeAsync(reqObj);
    verifyResponse((Source) response.get(3000, TimeUnit.MILLISECONDS));
  }
  public void testInvokeAsynchHandler() throws Exception {
    System.out.println("testInvokeAsynchHandler");
    AsyncHandler handler = new AsyncHandler() {
      public void handleResponse(Response response) {
        try {
          verifyResponse((Source) response.get());
          asyncHandlerCalled = true;
        } catch (Exception ex) {
          handlerException = ex;
        }
      }
    };
    StreamSource reqObj = new StreamSource(new StringReader(reqPayload));
    Future future = createDispatch().invokeAsync(reqObj, handler);
    future.get(1000, TimeUnit.MILLISECONDS);
    if (handlerException != null) throw handlerException;
    assertTrue("Async handler called", asyncHandlerCalled);
  }
  private Dispatch createDispatch() throws MalformedURLException {
    URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
    QName serviceName = new QName(targetNS, "EndpointBeanService");
    QName portName = new QName(targetNS, "EndpointPort");
    Service service = Service.create(wsdlURL, serviceName);
    Dispatch dispatch = service.createDispatch(portName, Source.class, Mode.PAYLOAD);
    return dispatch;
  }
  private void verifyResponse(Source result) throws IOException {
    Element resElement = DOMUtils.sourceToElement(result);
    String resStr = DOMWriter.printNode(resElement, false);
    assertTrue("Unexpected response: " + resStr, resStr.contains("<result></result>Hello"));
  }
}

Dispatch supports two usage modes, identified by the constants javax.xml.ws.Service.Mode.MESSAGE and javax.xml.ws.Service.Mode.PAYLOAD respectively:

Message: In this mode, client applications work directly with protocol-specific message structures. E.g., when used with a SOAP protocol binding, a client application would work directly with a SOAP message.

Message Payload (as in this sample): client applications work with the payload of messages rather than the messages themselves. E.g., when used with a SOAP protocol binding, a client application would work with the contents of the SOAP Body rather than the SOAP message as a whole.

Creating SOAP Messages Programmatically

In this tutorial we will learn how to create a javax.xml.soap.SOAPMessage programmatically using SOAPBody and SOAPElement objects and how to create one from a String. First of all the javax.xml.soap.SOAPMessage is the root class for all SOAP messages. As transmitted on the “wire”, a SOAP message is an XML document or a MIME message whose first body part is an XML/SOAP document.
A SOAPMessage object consists of a SOAP part and optionally one or more attachment parts. The SOAP part for a SOAPMessage object is a SOAPPart object, which contains information used for message routing and identification, and which can contain application-specific content. All data in the SOAP Part of a message must be in XML format.  The following code shows how you can code a SOAP Request:

private SOAPMessage createSOAPRequest() throws Exception
{
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        // SOAP Envelope
        SOAPEnvelope envelope = soapPart.getEnvelope();
        envelope.addNamespaceDeclaration("acme", "http://samples.saaj.jms");

        // SOAP Body
        SOAPBody soapBody = envelope.getBody();
        SOAPElement soapBodyElem = soapBody.addChildElement("employee", "acme");
        SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("id", "acme");
        soapBodyElem1.addTextNode("10");

        soapMessage.saveChanges();

        System.out.println("Request SOAP Message = ");
        soapMessage.writeTo(System.out);
        System.out.println();
        return soapMessage;
}

This is the SOAPMesage XML that will be created:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:acme="http://samples.saaj.jms">
   <SOAP-ENV:Header />
   <SOAP-ENV:Body>
      <acme:employee>
         <acme:id>10</acme:id>
      </acme:employee>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The following code, shows how to parse into a String the soapMessage object:

ByteArrayOutputStream outstream = new ByteArrayOutputStream();
soapMessage.writeTo(outstream);
String strMsg = new String(outstream.toByteArray());

Create a SOAPMessage from an XML String

Another strategy for creating a SOAPMessage implies using a SAXParser to create the SOAP Message from an XML String:

package org.example;

import java.io.IOException;
import java.io.StringReader;
import java.util.Iterator;
import javax.xml.parsers.*;
import javax.xml.soap.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class CreateSOAPfromXML {

public static SOAPElement createSOAPElementFromXMLString(String xmlString)
       throws ParserConfigurationException, IOException, SAXException
   {
       StringReader stringReader = new StringReader(xmlString);
       InputSource inputSource = new InputSource(stringReader);
       SAXParserFactory factory = SAXParserFactory.newInstance();
       factory.setNamespaceAware(true);
       SAXParser parser = factory.newSAXParser();
       SoapElementSaxHandler handler = new SoapElementSaxHandler();
       parser.parse(inputSource, handler);
       return handler.getSOAPElement();
   }

}

And here is the SoapElementHandler required for this class:

package org.example;

import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.soap.*;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SoapElementHandler extends DefaultHandler {
	private HashMap prefixURIMapping;
	private ArrayList uris;
	private SOAPElement rootElement;
	private SOAPElement currentElement;
	private SOAPFactory soapFactory;

	public SoapElementHandler() {
		prefixURIMapping = new HashMap();
		uris = new ArrayList();
		rootElement = null;
		currentElement = null;
	}

	public SOAPElement getSOAPElement() {
		return rootElement;
	}

	public void startDocument() throws SAXException {
		try {
			soapFactory = SOAPFactory.newInstance();
		} catch (SOAPException e) {
			throw new SAXException("Error: Can't create a SOAPFactory instance", e);
		}
	}

	public void startPrefixMapping(String prefix, String uri) {
		prefixURIMapping.put(uri, prefix);
		uris.add(uri);
	}

	public void characters(char ch[], int start, int length) throws SAXException {
		String str = String.valueOf(ch);
		if (length > 0)
			try {
				currentElement.addTextNode(str.substring(start, start + length));
			} catch (SOAPException e) {
				throw new SAXException("Error: Can't add a text node into SOAPElement from text", e);
			}
	}

	public void endElement(String uri, String localName, String qName) {
		if (currentElement != rootElement)
			currentElement = currentElement.getParentElement();
	}

	public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
		String prefix = (String) prefixURIMapping.get(namespaceURI);
		try {
			if (rootElement == null && currentElement == null) {
				rootElement = soapFactory.createElement(localName, prefix, namespaceURI);
				currentElement = rootElement;
			} else {
				currentElement = currentElement.addChildElement(localName, prefix, namespaceURI);
			}
			if (uris.size() > 0) {
				for (int i = 0; i < uris.size(); i++) {
					String uri = (String) uris.get(i);
					String pre = (String) prefixURIMapping.get(uri);
					currentElement.addNamespaceDeclaration(pre, uri);
				}

				uris.clear();
			}
			for (int i = 0; i < atts.getLength(); i++) {
				javax.xml.soap.Name attriName;
				if (atts.getURI(i) != null) {
					String attriPre = (String) prefixURIMapping.get(atts.getURI(i));
					attriName = soapFactory.createName(atts.getLocalName(i), attriPre, atts.getURI(i));
				} else {
					attriName = soapFactory.createName(atts.getLocalName(i));
				}
				currentElement.addAttribute(attriName, atts.getValue(i));
			}

		} catch (SOAPException e) {
			throw new SAXException(e);
		}
	}

}