Expose a Liferay Service as a Web Service
April 26th, 2010 by Bert WillemsTags:Java, Liferay, Spring, Web Services
In my previous article I showed you how you can implement a reusable Liferay Service without using Ext or the Service Builder utility. In this article we will take it one step further and expose the service we have created as web service again without using Ext or the Service Builder.
Liferay exposes the services based on Axis using a separate web application called tunnel-web. We will hook into tunnel-web so our service will be exposed in exactly the same way Liferay services are externalized. Let’s get started.
0. Project Setup
We will pick up from where we ended in the previous article. I have you haven’t followed the previous article you can download the initial project setup here. Please take a minute to familiarize yourself with the project structure.
We need to add a new dependencies to the pom of the service contract library:
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>portal-service</artifactId>
<version>${liferay.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>portal-kernel</artifactId>
<version>${liferay.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>portal-impl</artifactId>
<version>${liferay.version}</version>
<scope>provided</scope>
</dependency>
1. Prepare the portal
Make sure tunnel-web is installed in your application server. See the Liferay administration guide for details. The access to the web-service is restricted based on IP address. Open your portal-ext.properties and add the following lines to allow specified IP addresses to access to the web-services.
axis.servlet.hosts.allowed=127.0.0.1,SERVER_IP axis.servlet.https.required=false
2. Add the Service Classes
Ok lets get down to business. The first step is to create the web service class in the service contract library. Create a new class called HelloWorldServiceSoap in the package nl.devatwork.hello.world.service.http and copy the following code into it:
package nl.devatwork.hello.world.service.http;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import nl.devatwork.hello.world.service.HelloWorldServiceUtil;
import java.rmi.RemoteException;
public class HelloWorldServiceSoap {
private static Log _log = LogFactoryUtil.getLog(HelloWorldServiceSoap.class);
public static String sayHello(String name)
throws RemoteException {
String result;
try {
result = HelloWorldServiceUtil.sayHello(name);
} catch (Exception e) {
_log.error(e, e);
throw new RemoteException(e.getMessage());
}
return result;
}
}
This class wraps SOAP calls and maps them to the appropriate service call.
You can now build the service contract library by executing the following command in the /hello-world-service/ folder:
mvn clean package
Copy the resulting JAR file (/hello-world-service/target/hello-world-service-1.0.0-SNAPSHOT.jar) to the /lib/ext folder of your application server.
3. Apply Glue
The final step is a bit of handwork. We need to manually register the new service to the tunnel-web application. Open the server-config.wsdd located in the deploy directory/tunnel-web/WEB-INF folder of your application server. Add the following code just above the end of the XML:
<service name="Portlet_DevAtWork_HelloWorldService" provider="java:RPC" style="rpc" use="encoded"> <parameter name="wsdlTargetNamespace" value="urn:http.service.world.hello.devatwork.nl"/> <parameter name="wsdlServiceElement" value="HelloWorldServiceSoapService"/> <parameter name="wsdlServicePort" value="Portlet_DevAtWork_HelloWorldService"/> <parameter name="className" value="nl.devatwork.hello.world.service.http.HelloWorldServiceSoap"/> <parameter name="wsdlPortType" value="HelloWorldServiceSoap"/> <parameter name="typeMappingVersion" value="1.2"/> <operation xmlns:operNS="urn:http.service.world.hello.devatwork.nl" name="sayHello" qname="operNS:sayHello" soapAction=""> <parameter xmlns:tns="http://www.w3.org/2001/XMLSchema" qname="name" type="tns:string"></parameter> </operation> <parameter name="allowedMethods" value="sayHello"/> </service>
This will register our service within tunnel-web.
Start your application server and navigate to http://127.0.0.1:8080/tunnel-web/axis. Here you will find a list of all the services currently exposed by Liferay. In the list you will find our service (Portlet_DevAtWork_HelloWorldService). You can view the WSDL by clicking on the link behind the service.
That wasn’t to bad now was it? If you are to lazy to copy the code you can download the complete project here.
I hope you learned how you can expose services as web services in Liferay. In the upcoming article I will show you how you can add security to the web service.
That is it for now. Let me know if you have any comments or questions.

12 Replies to “Expose a Liferay Service as a Web Service”
October 11th, 2010 at 12:50
thanks a lot Bert for the article
November 5th, 2010 at 23:04
Great series of Articles Burt. I’m having trouble getting tunnel-web set up. Some notes on my environment, I’m running tomcat 5.5, liferay is NOT running in the root context, the application is running SSL on local host port 8443. Can you point me to a good reference for configuring tunnel-web under more advanced settings? I don’t get the list of services.
November 8th, 2010 at 22:16
AND, I was able to answer my own question after taking a weekend off.
January 26th, 2011 at 07:45
Thanks for the article. It is extremely helpful.
However, I’m running into an issue where I’m not finding certain Web service operations in Liferay. For example, the IGImageLocalServiceUtil.addImage method does not have an accompanying Liferay Web service operation. I would like to add this Web service operation so that my app can execute IGImageLocalServiceUtil.addImage from SOAP . Should I do it using the technique you listed in this article or would you recommend using the EXT or EXT plugin (for 6.0) – or would you recommend something else? Is this even possible using EXT or EXT plugin – I have to admit I’m not familiar with EXT or the EXT plugin.
I posted a similar question in the Liferay forum (http://www.liferay.com/community/forums/-/message_boards/message/7188341), but so far no one has responded. I would truly appreciate your advice. Thanks!
January 26th, 2011 at 17:06
Hello Lawrence,
It depends on your conditions and both scenarios will work but in general I recommend to create a service as described in my article which wraps the Liferay local API. I recommend this because, IMHO, modifying Liferays core is more likely to break when upgrading to a newer version.
Regards, Bert
February 10th, 2011 at 18:19
Hi,
I tink i’ve followe the tutorial step-by-step…
I can see the Web Service but when I try to invoke the method
i’ve the following exception:
18:16:35,085 ERROR [HelloWorldServiceSoap:18] java.lang.RuntimeException: HelloWorldService is not set
Any suggestion?
Tanks
Giancarlo
February 10th, 2011 at 18:35
Hello Giancarlo,
Can you tell me what version of Liferay you are using?
Regards,
Bert
May 27th, 2011 at 08:02
I have similar problem as Giancarlo
I’m using 6.06
July 5th, 2011 at 02:50
Thank you for the great tutorial.
I created this example, copied hello-world-service-1.0.0-SNAPSHOT.jar file to tomcat/lib/ext/ directory, and modified the .wsdd file (./tomcat/webapps/tunnel-web/WEB-INF/server-config.wsdd).
I restarted liferay portal.
When I navigate to tunnel-web/axis url, it causes page error:
HTTP Status 403 – Access denied for 120.153.106.89
type Status report
message Access denied for 120.153.106.89
description Access to the specified resource (Access denied for 120.153.106.89) has been forbidden.
Here is the public url:
http://www.ixsystems.com.au/tunnel-web/axis
Thanks
Sam
July 5th, 2011 at 09:03
Hello Sam,
First of all thank you for your feedback. I have updated the tutorial. I added the Portal preparation section which explains the IP block you encounter. I hope that solves your 403 error.
Regards,
Bert
July 5th, 2011 at 09:34
Good stuff,
Thanks a lot
Sam
September 13th, 2011 at 10:57
Is there any way to do the same thing but expose JAX-WS webservices which are Document/Literal? Ideally using something like Apache CXF?
Most web service stacks do not support RPC/Encoded anymore.