Datasports WebServiceListener Adapter
The Datasports WebServiceListener adapater is a sample adapter that shows how to create an input adapter which exposes a webservice. It is not a general-purpose component as-is, since the webservice interface is not particularly useful and is specified in code. It is meant as a guide or tutorial used in conjunction with this article.
The adapter features a configurable URI for the webservice, optional run time control interface, and a webservice that exposes 2 methods, with a corresponding output port for each. A remote call to either webmethod results in a tuple being sent out from the corresponding output port. The methods signatures are:
public boolean NewMessage(String notificationMessage) public boolean SetValue(String key, String value)
Both methods return a boolean indicating success in processing the call. For instructional and experimental purposes, both methods will fail (and return false) if the first parameter contains the string literal “FAIL” (case insensitive).
In addition to the adapter project and a StreamBase application that contains it, this package includes both Java and .Net clients for testing. The Java client is a non-GUI application with hard-coded test values, the .Net client is a WinForms application that lets the user enter parameters, invoke methods, and see results through a GUI.
The source for the adapter and both test applications which use it is available from the StreamBase Component Exchange. To load it, choose File | StreamBase Component Exchange…, and type WebServiceListener in the “Find in Title” field. Check the checkbox beside the title of the project, and choose Finish. This will import the project with all source into your current StreamBase Studio Workspace.
This article is not an in-depth tutorial on webservices, XML, Java, or creating a StreamBase adapter. For a detailed tutorial on creating a StreamBase adapter, see the article on the Datasports DirectoryWatcher adapter at directorywatcher.datasports.ca. A good starting point on JAX-WS can be found here:
What this article will cover is the specifics of how the Datasports WebServiceListener was implemented, in the hopes that it will serve as a useful starting point for others looking to do something similar. A webservice adapter may be a viable alternative to using the StreamBase client libraries for certain system integration projects.
The service itself is implemented in the class ServiceImplementation. An instance of this class is created and controlled by the WebServiceListener adapter class, which implements the IServiceListener interface used by ServiceImplementation to notify the adapter when its web methods are called.
The ServiceImplementation class imports the following packages:
import javax.jws.WebMethod; import javax.jws.WebService; import javax.xml.ws.BindingType; import javax.xml.ws.Endpoint;
And uses the following attributes:
@WebService @BindingType(value="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/") @WebMethod
The @WebService and @BindingType attributes can be found applied to the class itself, while @WebMethod is used to expose or hide individual methods.
2.1 WSDL Export
To allow other Java applications to add a reference to the webservice, we can generate a WSDL file using the wsgen utility (from the WebServiceListener project directory) as follows:
>wsgen -classpath java-bin -d wsdl-export -extension -wsdl:Xsoap1.2 ca.datasports.sb.webservicelistener.ServiceImplementation
For convenience, this script has been included as generate-wsdl.export.bat. If you
change the interface of the ServiceImplementation class, you must regenerate these class files by running the included script. If you are developing on a platform other than Windows, you can use this .bat file as a guide to the necessary parameters for invoking wsgen.
A webservice reference or import can also be created by retrieving and parsing the WSDL from the running service, but using the WSDL file as the definition allows the import step to be done without requiring the service to be running. Also, I found that this was the most reliable way to get the import to work for the Java client.
For the .Net client, it’s easier to add the reference via the dynamic WSDL generated by the running service, so we will go over how to use both approaches.
2.2 WSDL Import – Java
To import the WSDL and generate proxy classes from our test application, we use the wsimport utility (from the WSListenerClient project directory) as follows:
>wsimport ..\WebServiceListener\wsdl-export\ServiceImplementationService.wsdl -extension -d wsdl-import
For convenience, this script has been included as generate-wsdl.export.bat. If you
change the interface of the ServiceImplementation class, you must regenerate these class files by running the included script. If you are developing on a platform other than Windows, you can use this .bat file as a guide to the necessary parameters for invoking wsimport.
Again, the -extension switch is critical for the SOAP1.2 over HTTP binding to work correctly. This operation will create the necessary proxy classes to allow us to make calls to the remote application. The contents of this folder must be added as a project reference as follows:
Select Project | Properties | Java Build Path | Add Class Folder, and navigate to the wsdl-import folder. With this done, you are ready to use the webservice and call its methods. To see how this is done, see the main() method in the WSListenerClient class. Note that the URL hard-coded in that application will not work on your machine unless it happens to be named the same as mine by some lucky coincidence. You will have to change it to the URI of the service.
When you run the service, a message is logged to the console that looks like:
Starting Web Service at URI: http://owner-PC:8080/WebServiceListener
Take this value and append “?wsdl” to the end of it for the URI to use in WSListenerClient. You should not have to change the QName value since it is machine-independent.
2.3 Service Reference – .Net
As with the Java sample, the .Net sample has the URI of the service hard-coded, including the machine name. To correct this to work on your machine, open the project in VS2008, and find the Service Reference called SBServiceRef. Right-click it and choose “Configure Service Reference…” to open this dialog:
As for the Java client, you need to get the URI from the console and append “?wsdl” to the end, and enter this value in the Address: field.
With the reference updated, examine the source for the class frmWSTester. The Form1_Load() method initializes the connection to the webservice, and btnSendMessage_Click() and btnSetValue_Click() invoke the methods on the interface.
To add a reference to a webservice in a new .Net project, the steps are similar. Right-click the References or Service References item for your project in the solution explorer, and choose “Add Service Reference…”. Specify the address, choose Go, select the Service you want, enter a namespace for the reference’s proxy classes in your project, and you’re ready to instantiate and use the proxy classes as shown in the example of the frmWSTester class.
3. Properties and Control Interface
The Datasports WebServiceListener adapter has 3 properties:
- (boolean) Use Control Port: defaults to false. If set, include an input port to control the adapter’s operation.
- (boolean) Enabled: defaults to true. If set, adapter starts processing on initialization.
- (String) Base URI: defaults to “:8080/WebServiceListener”. The URI for the running service. It will be prepended with machine name, and this value must begin with : or /
The run time control interface is provided via the optional input port (enabled when Use Control Port is set to true). This input port’s schema represents a control interface used to change or configure the adapter’s behavior at run-time, as well as to enable and disable it. The input tuple includes fields which correspond to the adapter’s properties (except Use Control Port), and specifying a value for a field updates that property. Any field may be left null. After processing all non-null fields from the input tuple, the changes are applied and the JAX-WS webservice is updated.
Using this pattern provides a clear mechanism for a configuration management subsystem to retrieve adapter and operator configuration values from some source of configuration information (CSV file, XML file, DB, webservice, etc.), as well as for an administrative or control console UI to make run-time changes to a system’s operation. Where such a mechanism is not required, set Use Control Port to false and set all properties in StreamBase Studio at design time.
The root of all tuple processing occurs in the processTuple() method. Any adapter or operator which accepts tuples must implement this method. In the case of the Datasports WebServiceListener, processTuple() has a simple implementation – the tuple is parsed for property values, which are applied if they are found.
The Datasports WebServiceListener adapter is not really intended to be used as-is, but rather to serve as a starting point or a guide for developers who want to add webservice interfaces to StreamBase projects. It provides a design and implementation pattern and hopefully some useful code and pointers.
To use the adapter as-is, run the WebServiceListenerTesting.sbapp application, and call the methods on the running webservice using either or both of the client applications provided. Calls to the NewMessage() method result in tuples being sent out the MessagesOut stream (connected to output port #1 on the adapter), and calls to SetValue() result in tuples being sent on the KeyValuePairsOut stream (connected to output port #2 on the adapter).
To stop or start the webservice at run time, send in a tuple with Enabled set to false or true, respectively. Similarly, to change the URI of the running service, send in a tuple with BaseUri set to a valid value. Note that doing so will prevent the client applications from connecting unless they are modified to find the service at its new address.
In this article, we discussed the design and usage of an input adapter using JAX-WS. The sample covers exposing, configuring, stopping and starting the webservice, exporting and importing WSDL, calling the resulting service from Java and .Net clients, and generating outbound tuples in response to webmethod calls on the exposed webservice.
It is my hope that this article is somehow interesting or relevant to members of the StreamBase development community, and that it (and future articles) will spark some discussion around best practices and design and implementation of StreamBase solutions.
You are free to use the Datasports WebServiceListener adapter in whole or in part however you choose. Also, please take some time to post your comments, questions, or suggestions on this blog.