Liferay Web Services - How Do You Do It? (4.3.4)

A lot of people I run into at trainings and on consulting gigs ask this question:

 

"How do I access Liferay via Web Services?"

 

Well, there are 2 basic things you need:

1) A way to get the stubs for Liferay Web Services

2) Some sort of client app to access the portal's services

 

OK. Honestly, here is the easiest thing you can do to get started: Use Eclipse and download the Web Tools Platform (WTP) plugin. You can use the wizard to generate a Web Services client without writing a lick of code!

The 3 main steps:

1) Generate an Axis web service client


2) Call web services via your generated client


3) Use your generated client to access web services from the ext environment

 

I took most of this from a pretty good slide that Rich Sezov (who is doing a lot of the new Liferay docs) made. This slide is here: Liferay Web Services

Download that and follow the steps there.

In that example we are using a URL for a stock quote web service (non Liferay). This gets you the WSDL file to do the generation from Eclipse WTP. You need the WSDL file to get started with any web services client. If you've got this working, now the question is: "How do I get the WSDL for Liferay Web Services?"

Here is the URL you need for Liferay:

http://" + userIdAsString + ":" + password + "@localhost:8080/tunnel-web/secure/axis/" + serviceName

So for example, to get Organization data, use this URL:

http://2:test@localhost:8080/tunnel-web/secure/axis/Portal_OrganizationService

 

Look in the database in the User_ table to find an appropriate userId.

 

It should be as simple as that.

 

Now...

Another way to achieve the above is to use one of the Liferay samples. If you are a Java developer, download this:

 

Liferay Portal 4.3.4 Web Services Client
Java Stubs for Liferay Services (SOAP, Spring Remoting).

 

This will give you the jar files you need to access these services. Use these jar files to create a very simple webapp. So for a Tomcat instance, in your webapps directory, you will have a directory for your app, and in that directory it will have a standard WEB-INF (with a web.xml) and index.jsp. Very standard stuff. In WEB-INF/lib you will place all the jars. Especially important is the portal-client.jar. To access Liferay Organization data for example, you will have something like this in your index.jsp:

 

<%@ page import="com.liferay.client.portal.model.OrganizationSoap" %>
<%@ page import="com.liferay.client.portal.service.http.OrganizationServiceSoap" %>
<%@ page import="com.liferay.client.portal.service.http.OrganizationServiceSoapServiceLocator" %>
<%@ page import="java.net.URL" %>


<table>
<tr>
<th>Organizational Membership</th>
</tr>

<%
long userId = 0;
try {
    userId = Long.parseLong(userIdAsString);
} catch (Exception e) {
    e.printStackTrace();
}

OrganizationServiceSoapServiceLocator locator = new OrganizationServiceSoapServiceLocator();

OrganizationServiceSoap soap = locator.getPortal_OrganizationService(_getURL(userIdAsString, "Portal_OrganizationService"));

OrganizationSoap[] organizations = soap.getUserOrganizations(userId);

for (int i = 0; i < organizations.length; i++) {
    OrganizationSoap organization = organizations[i];
%>
    <tr>
        <td><%= organization.getName() %></td>
    </tr>
<%
}
%>
</table>

<%!
private URL _getURL(String userIdAsString, String serviceName) throws Exception {

    // Unathenticated url

    String url = "http://localhost:8080/tunnel-web/axis/" + serviceName;

    // Authenticated url

    if (true) {
        String password = "test";

        url = "http://" + userIdAsString + ":" + password + "@localhost:8080/tunnel-web/secure/axis/" + serviceName;
    }

    return new URL(url);
}
%>

 

Lastly, but not LEAST!!!

Another example that Liferay provides is here:

sample-portal-client-portlet-4.3.4.1.war

Take a good look at this sample and you will see almost everything you need. I usually am in the habit of telling people to "just look here" but I think it works better with all the above stuff explained first. =)

 

Hope it works for you and good luck!

 

 

Blogs
Great tutorial, James!

An easy way if you're on the same machine as the running Liferay instance (i.e., your developer machine) to get the Liferay WSDL is to hit it with the following URL:

http://localhost:8080/c/wsrp

If you're not on the same machine, though, James' method is the way to do it. :-)
I guess this is pretty late, but I just found this and I think it's a great tutorial too!
Great, but does not authenticate: 403. I am trying with v.5.0.1RC. Also, do we need to use same 'soap'-like classes even with '/secure/spring'?

Where is "just look here" indeed, where are some working samples (EJB, Hessian, RMI, JSON, etc.)
sample-portal-client-portlet.war portlet is throwing (401)Unauthorized exception in AxisFault. Is there a way make it work?

I tried with couple of users by changing the password in view.jsp, but some reason it is still not working.

Thanks in advance.
Hi James, and thank you for your valuable post... bit after many days trying to access Liferay's SOAP Web Services from soapui and other tools, stil I'm not able to get success...

Using the endpoint "http://<numericuserid>:<password>@<host>:8080/tunnel-web/secure/axis/Portal_UserService" I get the error "This request requires HTTP authentication ().".

Note that also the "liferay-portal-client" portlet it's not able to run...

Please, could you help me?

Thank you very much in advance!

Ivano Carrara
I resolved about the authentication ... was my fault!

Using SOAP Web Services client tools I have to put the exact credentials in the right place ... My fault was that I add the credentials directly in the URL, for example: http://<userId>:<password>@localhost:8080/tunnel-web/........

Excuse me!!

Still I'm getting the message "No such operation 'addUser'" trying to add a new user from a SOAP Web Services call.

Please, could you address me abiut this last probem?

Thank you in advance!

Ivano Carrara
Resolved..... adding the below parameters to the request

<prefixId xsi:type="xsd:int">0</prefixId>
<suffixId xsi:type="xsd:int">0</suffixId>

(or the exact values, of course ....) you can add the new user!

James, excuse me for the invasion of your blog!

Thank you,
Ivano Carrara
I have the same error ("No such operation 'addUser' "). But i'm using the portal-client.jar
Besides this is the worst interface i ever saw i my life, My code is:


public void userTest() throws ServiceException, Exception {
UserServiceSoapServiceLocator locator = new UserServiceSoapServiceLocator();
UserServiceSoap service = locator.getPortal_UserService(getURL("Portal_OrganizationService", true));
UserSoap user = service.addUser(0, true, "", "", false, "Distrito", "Distrito@lal.com", "US", "distrito", "",
"", 0, 0, true, 01, 01, 1990, "district", null, false);
}

So i'm puting those suffix and prefixes as 0.. but i still have the same error... Can some one tell me where i can found some.. at least a bit of information about this api.. I have a client that want's to use this portal as a Newsletter publisher.. and i can't connect or even understand this api... How can some one did the services so complex and without a simple line of jdoc?

Thanks
I started using the web services from liferay. The output is basically a SOAP message. Is there a way to get output in JSON, since i am using pure html+javascript to get the data. Or is there a utility written to convert the SOAP message to a Javascript Object.
For JSON, start here:
http://www.liferay.com/community/wiki/-/wiki/Main/JSON+Service+API
hi , i saw the above code sinnipt, it useful. but i have the same code as standalone, i cannot add new user to the liferay database.
the following are my code
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package com.liferay.portal.events;

import com.liferay.client.soap.portal.model.UserSoap;
import com.liferay.client.soap.portal.service.ServiceContext;
import com.liferay.client.soap.portal.service.http.UserServiceSoap;
import com.liferay.client.soap.portal.service.http.UserServiceSoapServiceLocator;

import java.net.URL;
import java.rmi.RemoteException;
import java.util.Locale;

/**
*
* @author kumar.ganapathy
*/
public class lir {

public static void main(String ar[]) {
try{
long creatorUserId = 0;
boolean autoPassword = false;
boolean autoScreenName = false;
String openId = "";
java.util.Locale locale = new java.util.Locale("en_US");
String middleName = "";
int prefixId = 0;
int suffixId = 0;
int birthdayMonth = 3;
int birthdayDay = 23;
int birthdayYear = 1985;
String jobTitle = "";
//long[] groupIds = null;
long[] organizationIds = null;
long[] roleIds = null;
long[] userGroupIds = null;
boolean sendEmail = false;
ServiceContext serviceContext = new ServiceContext();
String remoteUser = "test";
String password = "test";
String screenName="praveekan";
String emailAddress="pravee@liferay.com";
String password1="password";
String firstName="pravee";
String lastName="kan";
long[] groupIds = null;
UserServiceSoapServiceLocator locatorUser = new UserServiceSoapServiceLocator();
UserServiceSoap soapUser = locatorUser.getPortal_UserService(_getURL(remoteUser, password, "Portal_UserService"));
UserSoap usoap= soapUser.addUser(10112, autoPassword,password1,password1,autoScreenName,screenName,emailAddress,openId,"ENGLISH",firstName,middleName,lastName,prefixId,suffixId, true,birthdayMonth,birthdayDay,birthdayYear, jobTitle, groupIds,organizationIds,roleIds,userGroupIds, sendEmail,serviceContext);
long[] uid={usoap.getUserId()};
soapUser.addUserGroupUsers(14502, uid);

}


catch(Exception e){
e.printStackTrace();
}
}
private static URL _getURL(String remoteUser, String password, String serviceName) throws Exception {
// Unathenticated url
// Unathenticated url
String url = "[http://127.0.0.1:8080/tunnel-web/axis/" + serviceName;
// Authenticated url
if (true) {
url = "[http://"+ remoteUser + ":" + password + "@10.1.11.93:9000/tunnel-web/secure/axis/" + serviceName+"?wsdl";
}
return new URL(url);
}
}

could any plz give me idea how to do this.

i have my liferay in separate machine, i can get the sevice wsdl on browser, when i try to add user to, i cant..

plz its too urgent... could you plz guide me.... am dham new to this....
Look at the errors or warnings in the log, that will give you more information. Also see if there is a difference if you do it all on the same machine, could be permissions or network access?
A couple notes on how I eventually got this to work...

The client library (for version 5.2.3) is missing at least one JAR file: axis-saaj-1.4.jar.

Also, you are required to use the user's numeric (database) ID and not the user's logon ID in order to call these services. This is a real pain in the neck from an administrative perspective. Nobody knows who user "243" is, instead they know something like "ws-service-user" or something symbolic like that.

Lastly, I have tried to make use of the other remoting options, such as Hessian, Burlap and Spring HttpInvoker, however it is clear that LifeRay has never tested these.

Thanks for you blog post, there's an utter lack of documentation on this subject and the information that is available is largely incorrect!

Good luck!
ps. the HTML layout for your blog is broken in FireFox, user comments get cut off on the right hand side.
Hi Sam,

I have investigated this issue of sending numeric id and user id. I am successfully been able to hit services with logon id. Can you please check the response of Praveen, whether it works for you.

Thx.
Hi Praveen,

I am using liferay webservices using following method. After a week of research on webservices of liferay I got some clue and got succeeded.

Steps:

1. Start your tomcat and see if u can view http://localhost:8080/tunnel-web/axis link in browser.

2. In liferay-portal project u will find portal-client folder. In that run ant build with target "build-client" and it will generate portal-client.jar.

3. Copy the jar file in your client project and use following code and u will hit the server response.

try{
String username = "test@liferay.com";
String password = "test";
GroupServiceSoapServiceLocator gplocatore = new GroupServiceSoapServiceLocator();
java.net.URL gpurl = new java.net.URL(gplocatore.getPortal_GroupServiceAddress());
Portal_GroupServiceSoapBindingStub group = new Portal_GroupServiceSoapBindingStub
(gpurl, gplocatore);
group.setUsername(username);
group.setPassword(password);
String soap = group.getUsername();
System.out.println(soap);
}catch(Exception e){
e.printStackTrace();
}
Sorry man instead of last two lines use following lines.

GroupSoap soap = group.getGroup(groupId);
System.out.println(soap.getName());

This style is working.
Hi James,

This is a real good Post on Liferay web services.

I followed all the steps as per the post.
But, the thing is I'am not getting any response in my view.jsp when I try to call the webservice "soap.getUserOrganizations".

Guyz, please need help.

Thanks,
nagaraj.
I suggest looking at the errors in the console and/or log. This post is valid for Liferay 4.3.4.
HI James,

Thanks for the response.

Am not getting any exceptions. It's just that I'am not getting any response.
let me brief on steps I followed,

I have tomcat-6.0.26 running Liferay-6.0.5,
1) created a, Liferay plugin Project from my eclipse.
2) downloaded the liferay-portal-client-4.3.4.zip, unzipped and copied following jars,

activation.jar
axis.jar
commons-discovery.jar
jaxrpc.jar
mail.jar
saaj.jar
wsdl4j.jar
commons-logging.jar
portal-client.jar

to my portlet project's, lib folder.

3) my view.jsp looks like this,

<%@ page import="com.liferay.client.portal.model.OrganizationSoap" %>
<%@ page import="com.liferay.client.portal.service.http.OrganizationServiceSoap" %>
<%@ page import="com.liferay.client.portal.service.http.GroupServiceSoapServiceLocator" %>
<%@ page import="com.liferay.client.portal.service.http.Portal_GroupServiceSoapBindingStub" %>
<%@ page import="com.liferay.client.portal.service.http.OrganizationServiceSoapServiceLocator" %>
<%@ page import="java.net.URL" %>


<table>
<tr>
<th>Organizational Membership</th>
</tr>

<%
long userId = 2;
try {
userId = Long.parseLong("2");
} catch (Exception e) {
e.printStackTrace();
}

OrganizationServiceSoapServiceLocator locator = new OrganizationServiceSoapServiceLocator();

OrganizationServiceSoap soap = locator.getPortal_OrganizationService(_getURL("2", "Portal_OrganizationService"));

OrganizationSoap[] organizations = soap.getUserOrganizations(userId);

for (int i = 0; i < organizations.length; i++) {
OrganizationSoap organization = organizations;
%>
<tr>
<td><%= organization.getName() %></td>
</tr>
<%
}%>

</table>

<%!
private URL _getURL(String userIdAsString, String serviceName) throws Exception {

// Unathenticated url

String url = "http://localhost:8080/tunnel-web/axis/" + serviceName;

// Authenticated url

if (true) {
String password = "test";

url = "http://" + userIdAsString + ":" + password + "@localhost:8080/tunnel-web/secure/axis/" + serviceName;
}

return new URL(url);
}
%>


4) then I run protlet project's build.xml and included the sample portlet into my liferay which is running.

5) Now, my portlet jsp(view.jsp) which got added to liferay is empty(blank page).

I'am not getting any response or any exceptions.

I tried to debug from my eclipse.

OrganizationSoap[] organizations = soap.getUserOrganizations(userId);, this is the line of code which gets the response. I debugged and found that "organizations" array is empty.



Hope U understood my problem.

need help

Thanks,
nagaraj.
HI James,

I successfully called the Liferay web services from my sample portlets. Thanks for your response.

Now, that when I use the HSQL(liferay default) as my database, I'am getting response for my web service call and I'am able to see the results in my view.jsp.

But when change HSQL to MySql( in portlet-ext.properties) I'am not getting any response.

The database properties(like host,port,username and password) are valid one. I'am telling this because the same is working good, when I check with ordinary portlets.

Only for portlets making web service calls are not working for MySQL database, only working for HSQL.

Need Help.

Thanks,
Nagaraj
Unfortunately, there is not much information to go on to help you. Look at the error log for exceptions, and please follow the Portal Administrator's Guide to make sure you changed the database properly.
hiiiiiiiiiii..........can anyone tell me how to do interportlet communcation in LIFERAY 6.......its very urgent as my manager has asked me to complete this task in a very short span of time.......plz plz its very urgent.......
Try the book Liferay In Action (appendix C): http://manning.com/sezov/
thnx James...i successfully called one portlet from another......

i want to do some web service in liferay..........can u please guide me through step by step to achieve WS using eclipse.......i am using LR6.0.6 bundled with Tomcat.....
thnx !!!
The WSDL files are here:

127.0.0.1/tunnel-web/axis

Once you can access the WSDL you can use any wizard to generate the client side. To add server IPs that can access that server's web services, look at the portal.properties file and overwrite that property in your portal-ext.properties file.
Hi James...thnx for replying.....but i dint get exactly...actually i have to consume complex web service and it is nested List i.e. List under List......and i am unable to do so James.....first i want to consume simple external webservices....and i wneed ur help in this James....a step by step procedure would be great from ur side.....

Thnx !!
Sorry, there is no step-by-step for that. It really is up to you to figure that out because it is not specific to portal/portlet. That is standard Java development stuff.