Invoking Web Services from your Flux Workflow

Flux’s RestAction is the go-to construct for users orchestrating Flux workflows that involve web service integration. Be it HTTP-based services or SOAP-based services that implement HTTP binding, RestAction comes very handy for developers. Flux has a WebServiceAction which talks SOAP exclusively for services that implement WS-* such as Addressing, Security etc. RestAction has neat XPath integration, which allows users to navigate the response using XPath query and bind the result to domain model that can be seamlessly used in your workflow context.

In this post, let us look at a simple Weather Web Service which supports both SOAP and HTTP binding. I will be using Eric’s simple test framework to demonstrate the use of RestAction and WebServiceAction in your Flux workflow.

Let us see how to invoke the Weather web service using the traditional WebServiceAction that uses the WSDL. We pass the zip code as a parameter to GetCityForecastByZIP operation and the response is handled using a JavaAction. In this case the response is bound to ForecastReturn complex type.

package flux.test;

import com.cdyne.ws.weatherws.Forecast;
import com.cdyne.ws.weatherws.ForecastReturn;
import flux.*;
import org.junit.Test;

import java.net.URL;
import java.util.Properties;

public class WeatherWebServicesTest extends AbstractFluxTest {

@Test
public void testWebServiceAction() throws Exception {
log.info("[START] FluxTest.testWebServiceAction");
String namespace = "/FluxFlowChart";

FlowChart flowChart = engineHelper.makeFlowChart(namespace);

WebServiceAction webServiceAction = flowChart.makeWebService("GET Weather Info");

// Specify the WSDL the web service action is to use.
webServiceAction.setWsdl(new URL("http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"));

// Specify the signature of the method to call.
webServiceAction.setListenerSignature("GetCityForecastByZIP(String)");

// Specify the arguments to pass to the method.
webServiceAction.setArgument(0, "59102");

JavaAction javaAction = flowChart.makeJavaAction("Java Action");
javaAction.setListener(WebServiceActionListener.class);

webServiceAction.addFlow(javaAction);

engine.put(flowChart);

waitForRuns(namespace, 1, 5, 30);

log.info("[END] FluxTest.testWebServiceAction");
}
}

The ActionListener implementation that processes the ForecastReturn from WebServiceAction.

https://bitbucket.org/aruld/flux-goodies/src/cef68b56496c/flux-web-services/src/flux/test/WebServiceActionListener.java

Let us invoke the same operation using RestAction, which uses the HTTP binding. Here we set the query parameter “ZIP” and bind the response to ForecastReturn POJO (generated using: xjc -wsdl http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl).

@Test
public void testRestActionGET() throws Exception {
log.info("[START] FluxTest.testRestActionGET");
String namespace = "/FluxFlowChart";

FlowChart flowChart = engineHelper.makeFlowChart(namespace);

RestAction restAction = flowChart.makeRestAction("GET Weather Info");

// Specify the URL the rest action is to use.
restAction.setBaseUrl(new URL("http://wsf.cdyne.com/WeatherWS/Weather.asmx/GetCityForecastByZIP"));

// Specify the Action type.
restAction.setActionType(RestActionType.GET);

// Specify the Response type.
restAction.setResponseType(ForecastReturn.class);

// Specify the query parameters to be sent as part of the request.
Properties queryParams = new Properties();
queryParams.put("ZIP", "59102");

restAction.setQueryParameters(queryParams);

JavaAction javaAction = flowChart.makeJavaAction("Java Action");
javaAction.setListener(RestActionListener.class);

restAction.addFlow(javaAction);

engine.put(flowChart);

waitForRuns(namespace, 1, 5, 30);

log.info("[END] FluxTest.testRestActionGET");
}

In this example, we are performing an XPath query that returns an array of Forecast elements.

@Test
public void testRestActionXPathArray() throws Exception {
log.info("[START] FluxTest.testRestActionXPathArray");
String namespace = "/FluxFlowChart";

FlowChart flowChart = engineHelper.makeFlowChart(namespace);

RestAction restAction = flowChart.makeRestAction("GET Weather Info");

// Specify the URL the rest action is to use.
restAction.setBaseUrl(new URL("http://wsf.cdyne.com/WeatherWS/Weather.asmx/GetCityForecastByZIP"));

// Specify the Action type.
restAction.setActionType(RestActionType.GET);

// Specify the query parameters to be sent as part of the request.
Properties queryParams = new Properties();
queryParams.put("ZIP", "59102");

restAction.setQueryParameters(queryParams);

// Specify the XML namespace, if one defined
Properties namespaces = new Properties();
namespaces.put("ws", "http://ws.cdyne.com/WeatherWS/");
restAction.setNamespaces(namespaces);

// Specify the XPath expression using the defined namespace
restAction.setXpathExpression("/ws:ForecastReturn/ws:ForecastResult/ws:Forecast");// this xpath returns an array of Forecast elements

// Specify the XPath response type.
restAction.setXpathResponseType(Forecast[].class);

JavaAction javaAction = flowChart.makeJavaAction("Java Action");
javaAction.setListener(RestActionListener.class);

restAction.addFlow(javaAction);

engine.put(flowChart);

waitForRuns(namespace, 1, 5, 30);

log.info("[END] FluxTest.testRestActionXPathArray");
}

In this example, we are performing an XPath query that returns the first Forecast element from the array.

@Test
public void testRestActionXPathPOJO() throws Exception {
log.info("[START] FluxTest.testRestActionXPathPOJO");
String namespace = "/FluxFlowChart";

FlowChart flowChart = engineHelper.makeFlowChart(namespace);

RestAction restAction = flowChart.makeRestAction("GET Weather Info");

// Specify the URL the rest action is to use.
restAction.setBaseUrl(new URL("http://wsf.cdyne.com/WeatherWS/Weather.asmx/GetCityForecastByZIP"));

// Specify the Action type.
restAction.setActionType(RestActionType.GET);

// Specify the query parameters to be sent as part of the request.
Properties queryParams = new Properties();
queryParams.put("ZIP", "59102");

restAction.setQueryParameters(queryParams);

// Specify the XML namespace, if one defined
Properties namespaces = new Properties();
namespaces.put("ws", "http://ws.cdyne.com/WeatherWS/");
restAction.setNamespaces(namespaces);

// Specify the XPath expression using the defined namespace
restAction.setXpathExpression("/ws:ForecastReturn/ws:ForecastResult/ws:Forecast[1]");// this xpath returns the first element from the list

// Specify the XPath response type.
restAction.setXpathResponseType(Forecast.class);

JavaAction javaAction = flowChart.makeJavaAction("Java Action");
javaAction.setListener(RestActionListener.class);

restAction.addFlow(javaAction);

engine.put(flowChart);

waitForRuns(namespace, 1, 5, 30);

log.info("[END] FluxTest.testRestActionXPathPOJO");
}

In this example, we are performing an XPath query that returns an attribute of ForecastReturn element.

@Test
public void testRestActionXPathAttribute() throws Exception {
log.info("[START] FluxTest.testRestActionXPathAttribute");
String namespace = "/FluxFlowChart";

FlowChart flowChart = engineHelper.makeFlowChart(namespace);

RestAction restAction = flowChart.makeRestAction("GET Weather Info");

// Specify the URL the rest action is to use.
restAction.setBaseUrl(new URL("http://wsf.cdyne.com/WeatherWS/Weather.asmx/GetCityForecastByZIP"));

// Specify the Action type.
restAction.setActionType(RestActionType.GET);

// Specify the query parameters to be sent as part of the request.
Properties queryParams = new Properties();
queryParams.put("ZIP", "59102");

restAction.setQueryParameters(queryParams);

// Specify the XML namespace, if one defined
Properties namespaces = new Properties();
namespaces.put("ws", "http://ws.cdyne.com/WeatherWS/");
restAction.setNamespaces(namespaces);

// Specify the XPath expression using the defined namespace
restAction.setXpathExpression("/ws:ForecastReturn/ws:City/text()");// this xpath returns the name of the city

// Specify the XPath response type.
restAction.setXpathResponseType(String.class);

JavaAction javaAction = flowChart.makeJavaAction("Java Action");
javaAction.setListener(RestActionListener.class);

restAction.addFlow(javaAction);

engine.put(flowChart);

waitForRuns(namespace, 1, 5, 30);

log.info("[END] FluxTest.testRestActionXPathAttribute");
}

The ActionListener implementation that processes various results from the RestAction is shown below.
https://bitbucket.org/aruld/flux-goodies/src/cef68b56496c/flux-web-services/src/flux/test/RestActionListener.java

Here is a screenshot of the test output from Intellij.

flux_web_services

You need to toss in the following jars from Flux distribution:

flux.jar
lib/restaction.jar
lib/webserviceaction.jar
lib/commons-logging-1.1.1.jar
examples/software_developers/web_services/lib/weatherws-generated.jar

Test dependencies include:

log4j-1.2.15.jar
junit-4.9.jar


Download the latest Flux 7.11 version here and check it out. The samples are available in flux-goodies bitbucket repository. You can also find more samples ($FLUX_HOME/examples/software_developers/web_services and $FLUX_HOME/examples/software_developers/rest_services) in the latest Flux 7.11.2 distribution. Enjoy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s