How to implement a SOAP client using JAX-WS Liferay infrastructure
1. Overview
-
Implementation of the calculator-api module. This module defines the APIs that each application can invoke to use the services of arithmetic operations (addition, subtraction, division and multiplication);
-
Implementation of the calculator-service module. This module implements the APIs defined by the calculator-api module and acts as a client to the SOAP Calculator service;
-
Implementation of the calculator-gogo-shell module. This module implements the Gogo Shell commands that use the APIs defined by the calculator-api module to perform the arithmetic operations;
-
Implementation of the calculator-web module. This module implements a standard MVC portlet that uses the APIs defined by the calculator-api module to perform the arithmetic operations.
-
calculator-api
-
Calculator is the interface that defines the arithmetic operations between two integers;
-
-
calculator-service
-
CalculatorClientImpl implements the APIs defined by the Calculator interface and acts as a client to the SOAP Calculator service;
-
-
calculator-web
-
AddOperationMVCActionCommand: MVC Action Command of the Calculator Web Module for the request of the addition operation;
-
-
calculator-gogo-shell
-
CalculatorCommand: Gogo Shell Commands of the Calculator Gogo Shell Module.
-
1 - Implementation of the SOAP client
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.cz.swsamuraj:gradle-jaxws-plugin:0.6.1"
}
}
apply plugin: "cz.swsamuraj.jaxws"
dependencies {
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "4.4.0"
compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
compileOnly project(":modules:calculator:calculator-api")
}
jaxws {
wsdlDir = 'src/main/resources/META-INF/wsdl'
generatedSources = 'generatedsources/src/main/java'
}

Figure 4 - Java classes generated by the Gradle wsImport task starting from the WSDL of the SOAP Calculator service.
package it.dontesta.labs.liferay.webservice.calculator.client.soap;
...
/**
* @author Antonio Musarra
*/
@Component(immediate = true, property = {}, service = Calculator.class)
public class CalculatorClientImpl implements Calculator {
@Override
public int add(int number1, int number2)
throws CalculatorOperationException {
try {
return _getService().add(number1, number2);
}
catch (CalculatorServiceException cse) {
throw new CalculatorOperationException(cse.getMessage(), cse);
}
}
@Override
public int divide(int number1, int number2)
throws CalculatorOperationException {
try {
return _getService().divide(number1, number2);
}
catch (CalculatorServiceException cse) {
throw new CalculatorOperationException(cse.getMessage(), cse);
}
}
@Override
public int multiply(int number1, int number2)
throws CalculatorOperationException {
try {
return _getService().multiply(number1, number2);
}
catch (CalculatorServiceException cse) {
throw new CalculatorOperationException(cse.getMessage(), cse);
}
}
@Override
public int subtract(int number1, int number2)
throws CalculatorOperationException {
try {
return _getService().subtract(number1, number2);
}
catch (CalculatorServiceException cse) {
throw new CalculatorOperationException(cse.getMessage(), cse);
}
}
private CalculatorSoap _getService() throws CalculatorServiceException {
if (Validator.isNull(_calculatorSoap)) {
try {
org.tempuri.Calculator calculator =
new org.tempuri.Calculator();
_calculatorSoap = calculator.getCalculatorSoap();
}
catch (WebServiceException wse) {
throw new CalculatorServiceException(wse.getMessage(), wse);
}
return _calculatorSoap;
}
else {
return _calculatorSoap;
}
}
private CalculatorSoap _calculatorSoap;
}
From this moment we can use the Calculator service on any module. Who uses the service is absolutely abstract from the fact that the implementation uses external SOAP services.
2 - Implementation of Gogo Shell commands
package it.dontesta.labs.liferay.webservice.calculator.gogoshell;
import it.dontesta.labs.liferay.webservice.calculator.api.Calculator;
...
/**
* @author Antonio Musarra
*/
@Component(
property = {
"osgi.command.function=add",
"osgi.command.function=divide",
"osgi.command.function=multiply",
"osgi.command.function=subtract",
"osgi.command.scope=calculator"
},
service = Object.class
)
public class CalculatorCommand implements Calculator {
public int add(int number1, int number2)
throws CalculatorOperationException {
return getCalculatorService().add(number1, number2);
}
...
@Reference(policyOption = ReferencePolicyOption.GREEDY)
private volatile Calculator _calculator;
}
Once the module has been deployed, we have the commands to make the arithmetic operations available. Just connect to the Gogo Shell and try.
3 - Implementation of Calculator Web
package it.dontesta.labs.liferay.web.calculator.portlet.action;
import it.dontesta.labs.liferay.webservice.calculator.api.Calculator;
...
/**
* @author Antonio Musarra
*/
@Component(
immediate = true,
property = {
"javax.portlet.name=" + CalculatorAppPortletKeys.CALCULATOR_SOAP_APP,
"mvc.command.name=/calculator/add-operation"
},
service = MVCActionCommand.class
)
public class AddOperationMVCActionCommand extends BaseMVCActionCommand {
@Override
protected void doProcessAction(
ActionRequest actionRequest, ActionResponse actionResponse)
throws Exception {
_handleActionCommand(actionRequest);
}
private void _handleActionCommand(ActionRequest actionRequest) {
try {
int term1 = ParamUtil.getInteger(
actionRequest, CalculatorAppWebKeys.ADD_OPERATION_TERM_1);
int term2 = ParamUtil.getInteger(
actionRequest, CalculatorAppWebKeys.ADD_OPERATION_TERM_2);
int result = _calculator.add(term1, term2);
actionRequest.setAttribute(
CalculatorAppWebKeys.ADD_OPERATION_RESULT, result);
}
catch (SOAPFaultException soapfe) {
SessionErrors.add(actionRequest, soapfe.getClass(), soapfe);
}
catch (WebServiceException wse) {
SessionErrors.add(actionRequest, wse.getClass(), wse);
}
catch (Exception e) {
SessionErrors.add(
actionRequest, "calculatorOperationError", e.getMessage());
}
}
@Reference(policyOption = ReferencePolicyOption.GREEDY)
private Calculator _calculator;
}
The following figures show the simple calculator in action.

Figure 8 - Still division by zero! Example of the GUI in case of error obtained from the execution of the operation
4 - Configuration of the JAX-WS API and CXF EndPoints
- CXF EndPoints
- JAX-WS API
If we want to be picky, we could run the services "(objectClass=javax.xml.ws.spi.Provider)" command from Gogo Shell to verify the JAX-WS API bridge has been properly configured. You should get it in output when shown in the figure below.
5 - Conclusions
-
The SOAP service we want to use requires an SSL/TLS Mutual authentication
-
The SOAP service we want to access requires WS-Security









