Friday, November 5, 2010

Web Service

Introduction

In general, web services are resources which may be called over the HTTP protocol to return data. They are platform-independent, allowing communication between applications on different operating systems and application servers. When the database entries are generated by ServiceBuilder, web services can be generated as well based on Apache Axis. As a result, nearly all of the backend API calls can be made using web services. Java clients may be generated from Web Service Definition Language (WSDL) using any number of tools (Axis, Xfire-CXF, JAX-RPC, and so on). Apache Axis is essentially a Simple Object Access Protocol (SOAP) engine—a framework for constructing SOAP processors such as clients, servers, gateways, and so on.
This document will show how to use the web services of liferay portal. Specially, it shows how to build web services and how manage organizations, users, User groups and roles.

Using Web services

When Liferay portal is up in your local machine, type the following URL in the browser. You will get a list of web services.
[http://127.0.0.1:8080/tunnel-web/axis]
[http://127.0.0.1:8080/tunnel-web/secure/axis]

What's happening?#

The portal uses Apache Axis to generate web services. The default Axis configuration is specified in the server-config.wsdd file under the /portal/tunnel-web/ docroot/WEB-INF folder. When you double-click on the target deploy in the Ant view, the file server-config.wsdd under the /portal/tunnel-web/docroot/WEBINF folder will be merged with the server-config.wsdd file under the /ext/extweb/ docroot/WEB-INF folder. Therefore, when you type http://127.0.0.1:8080/tunnel-web/axis in your browser, you will see a list of SOAP services.
To access a service remotely, the host must be allowed via the portal-ext. properties properties file. After that, the user must have permission to access the portal resources. The default settings to access a service remotely are specified in the portal.properties file as follows:
axis.servlet.hosts.allowed=127.0.0.1,SERVER_IP
axis.servlet.https.required=false
The code above shows the IPs to access the Axis servlet. You can input a blank list to allow any IP to access this servlet. SERVER_IP will be replaced with the IP of the host server. By default, 127.0.0.1 is the IP for local host. This is the reason that you can access web services only by the IP 127.0.0.1, and not localhost. Of course, you can use a domain name such as www.bookpub.com if you had set the mapping between 127.0.0.1 and www.bookpub.com in the hosts file.

Build custom WSDD #

Supposed the service.xml is at src/com/ext/portlet/reports of the folder $EXT_HOME/ext-impl. In order to build custom WSDD, we need to add the following lines after the lines
<target name="build-service-portlet-playerstats">
<antcall target="build-service">
<param name="service.file" value="src/com/xos/playerstats/portal/service.xml" />
</antcall>
</target>
in $EXT_HOME/ext-impl/build-parent.xml
<target name="build-wsdd-portlet-reports">
<antcall target="build-wsdd">
<param name="service.file" value="src/com/ext/portlet/reports/service.xml" />
</antcall>
</target>
And use the Ant Target "build-wsdd-portlet-reports" to generate WSDD files.

Add custom operations #

for example:
package com.ext.portlet.reports.service.impl;
import com.ext.portlet.reports.service.base.ReportsEntryServiceBaseImpl;
public class ReportsEntryServiceImpl extends ReportsEntryServiceBaseImpl {
public String LoadArticle () {
return "Test";
}
}
then build services and wsdd as:
ant build-service-portlet-reports
ant build-wsdd-portlet-reports

Build client #

Create a folder ext-client at $EXT_HOME
Add namespaceMapping.properties and build.xml at $EXT_HOME/ext-client
Add build-common-java.xml at $EXT_HOME
Type: ant build-client

namespaceMapping.properties #

com.my.client.soap.portlet.organization.model=[http://model.organization.portlet.my.com]
com.my.client.soap.portlet.organization.service.http=urn:http.service.organization.portlet.my.com

build.xml#

<?xml version="1.0"?>
<project name="ext-client" basedir="." default="compile">
 <import file="../build-common-java.xml" />
 <property name="jar.file" value="${ant.project.name}" />
 <property name="client.url" value="[http://localhost:8080/tunnel-web/axis"] />
 <target name="jar" depends="compile">
  <jar
   jarfile="${jar.file}.jar"
  >
   <fileset dir="classes" />
   <fileset dir="src" />
  </jar>
  <copy file="ext-client.jar" todir="${project.dir}/ext-lib/development" />
 </target>
 <target name="build-client" depends="clean">
  <echo message="Make sure the server is listening on ${client.url}." />
  <echo message="" />
  <delete dir="src" />
  <mkdir dir="src" />
  <java
   classname="com.liferay.portal.tools.PortalClientBuilder"
   classpathref="project.classpath"
   failonerror="true"
   fork="true"
   newenvironment="true"
  >
   <arg value="${project.dir}/ext-web/docroot/WEB-INF/server-config.wsdd" />
   <arg value="src" />
   <arg value="namespaceMapping.properties" />
   <arg value="${client.url}" />
  </java>
  <antcall target="jar" />
 </target>
</project>

build-common-java.xml#

<?xml version="1.0"?>

<project name="build-common-java" xmlns:antelope="antlib:ise.antelope.tasks">
 <import file="build-common.xml" />

 <if>
  <and>
   <equals arg1="${app.server.type}" arg2="tomcat" />
   <antelope:endswith string="${app.server.portal.dir}" with="/portal-web/docroot" />
  </and>
  <then>
   <property name="portal-impl.classes.dir" value="${project.dir}/portal-web/docroot/WEB-INF/classes" />
  </then>
  <else>
   <property name="portal-impl.classes.dir" value="${project.dir}/portal-impl/classes" />
  </else>
 </if>

 <target name="clean">
  <delete dir="classes" />
  <delete dir="test-classes" />
  <delete dir="test-results" />
  <delete file="${jar.file}.jar" failonerror="false" />
  <delete dir="${java2html.dir}" />
  <delete dir="${javadoc.dir}" />
 </target>

 <target name="compile">
  <mkdir dir="classes" />

  <copy todir="classes">
   <fileset dir="src" excludes="**/*.java" />
  </copy>

  <if>
   <equals arg1="${javac.compiler}" arg2="modern" />
   <then>
    <javac
     classpathref="project.classpath"
     compiler="${javac.compiler}"
     debug="${javac.debug}"
     deprecation="${javac.deprecation}"
     destdir="classes"
     fork="${javac.fork}"
     memoryMaximumSize="${javac.memoryMaximumSize}"
     nowarn="${javac.nowarn}"
     srcdir="src"
    />
   </then>
   <else>
    <javac
     classpathref="project.classpath"
     compiler="${javac.compiler}"
     debug="${javac.debug}"
     deprecation="${javac.deprecation}"
     destdir="classes"
     nowarn="${javac.nowarn}"
     srcdir="src"
    />
   </else>
  </if>
 </target>

 <target name="jar" depends="compile">
  <jar
   basedir="classes"
   jarfile="${jar.file}.jar"
  />
 </target>

 <target name="java2html">
  <java
   classname="j2h"
   classpathref="project.classpath"
   fork="true"
  >
   <arg line="-d ${java2html.dir} -js src -m 4" />
  </java>

  <replace dir="${java2html.dir}">
   <replacefilter
    token="stylesheet.css"
    value="java2html.css"
   />
  </replace>

  <move file="${java2html.dir}/stylesheet.css" tofile="${java2html.dir}/java2html.css" />

  <antcall target="javadoc" />

  <replace dir="${java2html.dir}">
   <include name="**/package-summary.html" />
   <replacefilter
    token="/\"
    value="/"
   />
  </replace>
 </target>

 <target name="javadoc">
  <mkdir dir="${javadoc.dir}" />

  <javadoc
   breakiterator="yes"
   classpathref="project.classpath"
   destdir="${javadoc.dir}"
   maxmemory="256m"
   packagenames="*.*"
   sourcepath="src"
   stylesheetfile="${project.dir}/tools/javadoc.css"
  />
 </target>

 <target name="deploy" depends="jar">
  <copy file="${jar.file}.jar" todir="${deploy.dir}" />
 </target>
</project>

CRUD on Organizations #

Simple code for Organization:
import java.net.URL;
import com.liferay.client.soap.portal.model.CompanySoap;
import com.liferay.client.soap.portal.model.OrganizationSoap;
import com.liferay.client.soap.portal.service.ServiceContext;
import com.liferay.client.soap.portal.service.http.CompanyServiceSoap;
import com.liferay.client.soap.portal.service.http.CompanyServiceSoapServiceLocator;
import com.liferay.client.soap.portal.service.http.OrganizationServiceSoap;
import com.liferay.client.soap.portal.service.http.OrganizationServiceSoapServiceLocator;
import com.liferay.client.soap.portal.service.http.UserServiceSoap;
import com.liferay.client.soap.portal.service.http.UserServiceSoapServiceLocator;
public class WSTest { 
 public static void main(String[] args) {
  // reference sql.data.com.liferay.portal.model.ListType.organization.status=12017
  try {
  String remoteUser = "test";
  String password = "test";
  String serviceOrgName = "Portal_OrganizationService";
  String serviceUserName = "Portal_UserService";
  String serviceCompanyName = "Portal_CompanyService";
  String virtualHost = "localhost"; 
  int statusId = 12017;
  long regionId = 0;
  long countryId = 0;
  long parentOrgId = 0;
  boolean recursable = true;  
  CompanyServiceSoapServiceLocator locatorCompany = new CompanyServiceSoapServiceLocator();
  CompanyServiceSoap soapCompany = locatorCompany.getPortal_CompanyService(
                       _getURL(remoteUser, password, serviceCompanyName));
  CompanySoap companySoap = soapCompany.getCompanyByVirtualHost(virtualHost);  
  UserServiceSoapServiceLocator locatorUser = new UserServiceSoapServiceLocator();
  UserServiceSoap soapUser = locatorUser.getPortal_UserService(_getURL(remoteUser, password, serviceUserName));
  long userId = soapUser.getUserIdByScreenName(companySoap.getCompanyId(), remoteUser);  
  OrganizationServiceSoapServiceLocator locator = new OrganizationServiceSoapServiceLocator();
  OrganizationServiceSoap soap = locator.getPortal_OrganizationService(_getURL(remoteUser, password, serviceOrgName));
  OrganizationSoap[] organizations = soap.getUserOrganizations(userId);
  for (int i = 0; i < organizations.length; i++) {
      OrganizationSoap organization = organizations[i];
      System.out.println(organization.getStatusId()+ "\t" + 
                                     organization.getOrganizationId() + "\t" + organization.getName() + "\t" + organization.getType());
  }
  // ServiceContext scxt = new ServiceContext();
  // OrganizationSoap org = soap.addOrganization(parentOrgId, "testOrg-MyOrg_Admin", 
                      //"regular-organization", recursable, regionId, countryId, statusId, "My Comments", scxt);
  // long users[] = {userId};
  // soapUser.addOrganizationUsers(org.getOrganizationId(), users);
  // soap.deleteOrganization(10232);
  }

  catch (Exception e) {
  e.printStackTrace();}
  }
  // Get URL
  private static URL _getURL(String remoteUser, String password, String serviceName) throws Exception {
  // Unathenticated url
  String url = "[http://127.0.0.1:8080/tunnel-web/axis/"] + serviceName;
  // Authenticated url
  if (true) {
  url = "[http://"] + remoteUser + ":" + password + "@127.0.0.1:8080/tunnel-web/secure/axis/" + serviceName;
  }
  return new URL(url);
  }
}
Note that
1) "sql.data.com.liferay.portal.model.ListType.organization.status=12017"
int statusId = 12017;
2) remove all users from the organization, before deleting the organization.

2 comments:

Anonymous said...

Valuable information. Lucky me I found your website by accident, and I am shocked why this accident did not happened earlier! I bookmarked it. Simpsons Tapped Out Hack

Unknown said...

What a fantabulous post this has been. Never seen this kind of useful post. I am grateful to you and expect more number of posts like these. Thank you very much. Six Guns Hack

Post a Comment

Share & Enjoy

Twitter Delicious Facebook Digg Stumbleupon Favorites More