This section describes the simplest and most frequently used means of creating and running a client, using a dynamically generated proxy in a two-part client-development scenario. All you need is a service interface and its mapping file (called an .xmap file), which contains additional information.
Creating a client is done at Compile-time. It consists of two steps:
Generating Service Interfaces - Generate the interface and mapping file using WSDL2Java.
Compiling the Interfaces - Use the Java compiler to compile this interface, copy the mapping file and use it in lookup to generate a dynamic proxy.
The client is run at Runtime. This consists of three steps:
Looking Up the Service - Dynamically generating the proxy. Use the ServiceClient.createProxy() method to look up the target service. During lookup, the WSDL of the target service is parsed and the proxy is generated. Now we have all that we need to call the service.
Calling the Service - Use the proxy obtained in the previous step to call the desired operation on the target service. Simply call one of the methods on the proxy. A SOAP message will be created and sent to the target service.
Exception Processing - Exceptions may occur during lookup or during a service call. Dealing with them is an optional part of Web service development.
The first step in creating a client is generating the service interface. This is done by the WSDL2Java tool. To use this tool, you need the url of the WSDL file of the service that the client is being created for.
The following command generates a client for the Hello Service, which has a wsdl located at http://localhost:6060/HelloService/wsdl:
WSDL2Java --url http://localhost:6060/HelloService/wsdl
The WSDL2Java tool has a number of optional parameters for selecting input, selecting output and debugging. The following command also creates a client for the Hello Service, but specifies that the client will be in a directory named client and the interfaces will be in the package examples.basics.invocation:
WSDL2Java --output-directory client --interface-package example.basics.invocation --url http://localhost:6060/HelloService/wsdl
By default, this command generates both synchronous and asynchronous methods in the interface. To generate only synchronous methods, include the option --output-language java (or -l java).
More information about the WSDL2Java tool and a full list of its optional switches can be found in WSDL2Java.
To compile the interfaces, run:
javac -classpath %WASP_HOME%\lib\wasp.jar client\*.java
(on Windows)
or
javac -classpath $WASP_HOME/lib/wasp.jar client/*.java
(on UNIX).
Using the same steps as in Generating the Service Interface, we generated a service interface for another Web service. It is shown in Example 75.
Example 75. Binding Interface with a Service
// Copyright WSO2 Inc. All rights reserved. // Use is subject to license terms. package example.basics.invocation; public interface HelloService { String hello(String msg); }
After compiling the interface, you can bind it with the service by using the lookup() method as shown in Example 76:
Example 76. Simple Client
// Copyright WSO2 Inc. All rights reserved. // Use is subject to license terms. package example.basics.invocation; import org.systinet.wasp.webservice.Registry; public class HelloClient { private static final String WSDL_URL = "http://localhost:6060/HelloService/wsdl"; public static void main(String[] args) throws Exception { HelloService proxy = (HelloService) Registry.lookup(WSDL_URL, HelloService.class); System.out.println(proxy.hello("world")); } }
Example 76 shows the easiest way of creating a proxy for a service. Simply use the Registry.lookup() method with WSDL URL and service interface as parameters. For more advanced client set-up, you have to use the ServiceClient class. See the API documentation for org.systinet.wasp.webservice.Registry and org.systinet.wasp.webservice.ServiceClient.
More advanced scenarios are also given in Client Settings.
![]() | Note |
---|---|
The Registry class is used both for simple lookup and runtime publishing. Please see Registry: Publish and Lookup. |
A Web service can be configured to require authentication, such as HTTP Basic Authentication with HTTP or HTTPS transport (the combination with HTTPS is more secure), before the SOAP request is processed. Some services even request HTTP Basic Authentication to retrieve WSDL.
Example 77 shows how to create a client and invoke a simple service that requires HTTP Basic Authentication both for WSDL retrieval and SOAP request. It creates a client with ServiceClient.create(String wsdlUrl, Map contextData), where the context data is a map containing the username and password.
Example 77. Creating a Client from WSDL Protected by HTTP Basic
import org.idoox.wasp.WaspSecurity; import org.systinet.wasp.webservice.ServiceClient; import java.util.HashMap; import java.util.Map; public class SecuredServiceClient { private static final String SERVER_URI = "http://host.example.com:6060"; // .NET default is 80 private static final String WSDL_URI = SERVER_URI + "/service/wsdl"; // /service?wsdl for .NET public static void main(String[] args) throws LookupException { // prepare properties - HTTP Basic password use for both WSDL retrieval and invocation Map props = new HashMap(3); props.put(WaspSecurity.HTTP_BASIC_USER_NAME, "admin"); // or WaspSecurity.HTTPS_BASIC_USER_NAME props.put(WaspSecurity.HTTP_BASIC_PASSWORD, "changeit"); // or WaspSecurity.HTTPS_BASIC_PASSWORD // create service client ServiceClient serviceClient = ServiceClient.create(WSDL_URI, props); // create a service proxy ServiceInterface service = (ServiceInterface) serviceClient.createProxy(ServiceInterface.class); // invoke service.method(); } }
To call the service, invoke methods on the proxy obtained by Registry.lookup() and/or ServiceClient.createProxy(). Note that you are not aware of the actual processes going on. WSO2 SOA Enablement Server hides all the work in the background. After the proxy is created, your code will not differ in any way from regular Java code. In other words, you can almost ignore the fact you are writing a client for a Web service.
JAX-RPC is becoming a Java standard for higher-level calling of Web services. This section describes part of the standard, the Dynamic Call interface. For more details on JAX-RPC, please refer to Java API for XML-Based RPC (JAX-RPC).
This interface is used in the following scenario:
When using Dynamic Call, follow this procedure to invoke the desired Web service:
Procedure 2. Using Dynamic Call
Create a Call Object – Call object represents information needed to invoke operation on service.
Fill the Call with Actual Values – Fill in information about parameters and values of other service operation in addition to operation name.
Invoke operation – Now you can use the completed Call object to invoke target operation. Simply call the invoke operation on the Call object.
If the service operation uses out or in-out parameters, you can get them using the getOutputParams method on the Call object.
![]() | Caution |
---|---|
Never use getOutputParams for out and in-out parameter Holders. |
and Example 78 explain the example found in examples/basics/invocation/JAXRPCClient.java:
Example 78. JAX-RPC Sample Client
// Copyright WSO2 Inc. All rights reserved. // Use is subject to license terms. package example.basics.invocation; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.Call; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; public class JAXRPCClient { static final String HELLO_SERVICE_NS = "http://wso2.com/wsdl/demo/basic/hello/server/"; static final String HELLO_OP_NS = "http://wso2.com/wsdl/demo/basic/hello/server/"; public static void main(String[] args) throws Exception { String serviceURI = "http://localhost:6060/demo/basic/HelloService"; ServiceFactory factory = ServiceFactory.newInstance(); Service service = factory.createService( new URL(serviceURI), new QName(HELLO_SERVICE_NS, "JavaService")); Call call = service.createCall(); QName operationName = new QName(HELLO_OP_NS, "hello"); Object[] callargs = new Object[] { "request to hello" }; Object ret = call.invoke(operationName, callargs); System.out.println("Service returned " + ret); } }
There are three steps in creating a Call object:
Get ServiceFactory instance
Create new service with ServiceFactory.createService(java.net.URL wsdlDocumentLocation, QName serviceName)
![]() | Caution |
---|---|
Only ServiceFactory.createService(java.net.URL wsdlDocumentLocation, QName serviceName) can be used! ServiceFactory.createService(QName serviceName) throws an UnsupportedOperationException. |
Create Call object itself
Creation of a Call object is shown in Example 79.
Example 79. Using JAX-RPC to Call a Service
// Get service factory instance ServiceFactory factory = ServiceFactory.newInstance(); // Create new service. Note the second parameter "JavaService" // is name of service and can be found in WSDL. Service service = factory.createService(new URL(serviceURI), new QName(HELLO_SERVICE_NS, "JavaService")); // create Call object for service Call call = service.createCall();
In advanced cases (multiple ports in the service) you will need to call createCall with more arguments. See the JAX-RPC specification for details.
After the Call object is obtained, it has to be filled with call parameters, as Example 80 shows:
A JAX-RPC call can throw java.rmi.RemoteException. The details of the particular exception are contained in its detail field. A list of additional possible exceptions can be found in Handling Exceptions.
During the lookup process, a WSDL document is fetched from the definitionURL and parsed into an internal representation. If there are errors in obtaining/parsing the document, a LookupException is thrown. An original exception that was thrown (such as java.io.IOException, or javax.wsdl.WSDLException) can be obtained using the inherited method org.idoox.util.WrappedException.getRootException().
Errors thrown during calls to the service fall into two categories:
Declared exceptions thrown from the service.
Exceptions of unexpected situations.
The first type of exception is regularly declared by the service (the SOAP Fault is declared in WSDL). These are mostly user-defined exceptions representing the error state of a Web service. After receiving such a fault in a SOAP message, WSO2 SOA Enablement Server tries to instantiate the same exception on the client side. The user can catch it in the usual try-catch block.
If WSO2 SOA Enablement Server does not succeed in exception instantiation, a Soap Fault Exception is thrown. In this case, you can use the methods provided by SoapFaultException to find the reason behind the error state.
UndeclaredThrowableException Sometimes in runtime an error state arises from a low-level fault like network, XML parsing or security problems. Unfortunately, the type of exception cannot be directly thrown by WSO2 SOA Enablement Server, which throws an instance of java.lang.reflect.UndeclaredThrowableException instead. You should catch this exception during the service call (as in Example 81), get the reason for its being thrown and throw the real exception, the most common of which are given in Table 2, “Exceptions Thrown from a WSO2 SOA Enablement Server Call” below.
The following table gives a list of the most common low-level exceptions that are thrown by WSO2 SOA Enablement Server:
Table 2. Exceptions Thrown from a WSO2 SOA Enablement Server Call
Exception | Description |
---|---|
java.net.ConnectException | Problems reading/writing the stream. |
java.net.ConnectException | Connection has been refused. |
java.net.SocketException | Low-level socket problems. |
javax.wsdl.WSDLException | Problem with parsing of WSDL. |
org.idoox.xmlrpc.MessageCreatingException | Error while creating the outgoing message. Call getRootException() to get the original exception. |
org.idoox.xmlrpc.MessageProcessingException | Error during processing the incoming message. Call getRootException() to get the original exception. |
org.idoox.security.ContextExpiredException | Signals that the security context has expired. Thrown by HttpDigest authentication mechanism after server-side specific time to live (TTL) of the security context. WSO2 SOA Enablement Server configuration allows you to change TTL values. More information about security exceptions thrown during the call can be found in the Client-side section in Client-Side Security. |
For more information on application level exceptions refer to Structured SOAP Fault Serialization.
Sometimes a client needs to send application-specific binary data to its peer. The preferred way of sending this data over SOAP is by using the SOAP with Attachments specification. This specification defines how data is serialized into a DIME or MIME Multi-part message and how this data is referenced.
WSO2 SOA Enablement Server for Java also supports WSDLs complying to WS-I Attachments Profile 1.0. These WSDLs can use elements or attributes of schema type ref:swaRef or attachment parts mapped via Content-Id. WSO2 SOA Enablement Server for Java supports both on client and service sides. This specification allows the inclusion of an arbitrary number of attachments to the message, for example an array of records representing a catalog item with images. These WSDLs are automatically recognized by the WSDL2Java tool and runtime. Note that clients using DIME attachments are not WS-I compliant.
The following sections describe in detail how to write a client capable of handling SOAP with Attachments. For information about services using SOAP with Attachments, see Service Using Attachments.
For attachment-enabled services, WSDL2Java generates an interface containing one of the MessageAttachment classes. The client creates an instance of the appropriate class, sets the data as input stream the same way as on the server, and invokes the method of the interface as shown in Example 82.
Example 82. Client Sending a Document
// Copyright WSO2 Inc. All rights reserved. // Use is subject to license terms.</font> package example.processing.attachments; import org.idoox.wasp.types.RequestMessageAttachment; import org.systinet.wasp.webservice.Registry; import java.io.ByteArrayInputStream; public class RequestAttachmentClient { public static void main(String[] args) throws Exception { AttachmentService service = (AttachmentService) Registry.lookup("http://localhost:6060/att", AttachmentService.class); ByteArrayInputStream requestInputStream = new ByteArrayInputStream("first line\nsecond line".getBytes()); RequestMessageAttachment att = new RequestMessageAttachment(); att.setContentType("text/plain"); att.setData(requestInputStream); System.out.println("Service returns : " + service.processAttachment(att)); } }
Please see the Attachments demo for a complete example of using the MessageAttachment class.
For large attachments or better performance it is necessary to use HTTP 1.1 chunked tranfer coding. The client code should follow this template:
Map clientContext = new HashMap(); clientContext.put(CallContext.HTTP_REQUEST_CHUNKING, "true"); ... ServiceClient serviceClient = ServiceClient.create(WSDL_URL, clientContext); ... service = (ServiceInterface) serviceClient.createProxy(ServiceInterface.class);
If a client receives an attachment from the service, it needs to have the necessary resources allocated until the client code processes the attachment. These resources are released for all attachments at the same time. SSJ must detect when these resources can be freed. This is done via a hook on the input streams' close methods. There are two deallocation methods specified in org.systinet.wasp.attachments.AttachmentsReleaseMethod:
Releases all resources as soon as one attachment stream is closed provided there are no other attachment streams open at the time. (default)
Releases the resources only when every attachment stream has been explicitly closed. This is preferable for processing attachments in a cycle.
AttachmentsReleaseMethod contains the static helper function setReleaseAttachmentMethod to set up the ServiceClient.
If the client does not release the attachment's resources, SSJ does the best it can to reclaim them and issues a warning about the problem.