Liferay Custom JSON web services on Multiple Tables
Objective: 
Create JSON web services for combination of multiple tables means prepare JSON
web services so that data should come from multiple tables which are related
each other.
Download CustomJsonWebservices
portlet from following location
You can find source and war file 
Note:  
Portlet developed in Liferay 6.1GA2 EE version
If you want deploy in CE version you just do changes in liferay-plugin-package.properties
Liferay 6.1 EE version
| 
name= CustomJsonWebservices 
module-group-id=liferay-ee 
module-incremental-version=1 
tags= 
short-description= 
change-log= 
page-url=http://www.liferay.com 
author=Liferay, Inc. 
licenses=EE 
liferay-versions=6.1.20 | 
Liferay 6.1 CE version
| 
name = CustomJsonWebservices 
module-group-id=liferay 
module-incremental-version=1 
tags= 
short-description= 
change-log= 
page-url=http://www.liferay.com 
author=Liferay, Inc. 
licenses=LGPL 
liferay-versions=6.1.1 | 
Procedure for deploy
portlet:
You can use war file and directly place in your portal deploy folder and
test or you can also use source to deploy portlet.
Once portlet is deployed successfully insert data in the following table
as shown in screens
json_employee
json_address
And test web service URLs
Liferay provide JSON web services so that we can use those services in
other systems.
Liferay providing two types of web services SOAP based and REST bases web
services.
Liferay JSON web services come under REST based web services.
Here we are talking about only rest based web services i.e. liferay JSON
web services. 
Liferay have built in ability can generate JSON web services by default
when we make remote-service true for
service builder.
But the services which created by default we can apply on only one table
means data can served from only one table or web services related to single
entity.
But in real scenario the default
web services not enough to full fill real requirement there we have write our custom
methods to produce JSON data. This pretty easy in liferay because liferay also
provides write custom methods for JSON web services in pluin portlet.
Note: 
Liferay have provided to generate service layer using service builder. We
will use servce builder to generate service layer classes and methods
Steps to produce Custom
JSON web services in Liferay Plugin portlet environment
The Following are the steps write custom methods to produce JSON web
services:
Step: 1
Create Plugin portlet in Liferay using liferay IDE and portlet is liferay
MVC portlet.
Step: 2
Create service bolder for plugin portlet
Open service.xml file and define data base tables and put remote-service
is true. When we put remote service true then it will create default JSON web
services.
| 
<?xml version="1.0"
  encoding="UTF-8"?> 
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD
  Service Builder 6.1.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_1_0.dtd"> 
<service-builder package-path="com.meera.jsonwebservices.db"> 
            <author>E5410</author> 
            <namespace>JSON</namespace> 
            <entity
  name="Employee" local-service="true" remote-service="true"> 
                        <column
  name="emplyeeId" type="long" primary="true"
  /> 
                        <column
  name="emplyeeName" type="String" /> 
                        <column
  name="employeeDesignation" type="String" /> 
                        <order
  by="asc"> 
                                    <order-column
  name="emplyeeId" /> 
                        </order> 
            </entity> 
            <entity
  name="Address" local-service="true" remote-service="true"> 
                        <column
  name="Id" type="long" primary="true"
  /> 
                        <column
  name="emplyeeId" type="long" /> 
                        <column
  name="employeeAddress" type="String" /> 
                        <order
  by="asc"> 
                                    <order-column
  name="emplyeeId"/> 
                        </order> 
                        <finder
  name="emplyeeId" return-type="Collection"> 
                                    <finder-column
  name="emplyeeId" /> 
                        </finder> 
            </entity> 
</service-builder> | 
Step: 3
Now we need add JSON Web service servelet in web.xml of porltet. So that
it will get web services exposing ability.
| 
<?xml version="1.0"
  encoding="UTF-8"?> 
<web-app id="WebApp_ID"
  version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 
            <display-name>CustomJsonWebservices-portlet</display-name> 
            <filter> 
         <filter-name>Secure JSON Web
  Service Servlet Filter</filter-name> 
         <filter-class>com.liferay.portal.kernel.servlet.PortalClassLoaderFilter</filter-class> 
         <init-param> 
          <param-name>filter-class</param-name> 
          <param-value>com.liferay.portal.servlet.filters.secure.SecureFilter</param-value> 
         </init-param> 
         <init-param> 
          <param-name>basic_auth</param-name> 
          <param-value>true</param-value> 
         </init-param> 
         <init-param> 
          <param-name>portal_property_prefix</param-name> 
          <param-value>jsonws.servlet.</param-value> 
         </init-param> 
      
  </filter> 
      
  <filter-mapping> 
         <filter-name>Secure JSON Web
  Service Servlet Filter</filter-name> 
    
      <url-pattern>/api/jsonws/*</url-pattern> 
      
  </filter-mapping> 
      
  <servlet> 
         <servlet-name>JSON Web Service
  Servlet</servlet-name> 
         <servlet-class>com.liferay.portal.kernel.servlet.PortalClassLoaderServlet</servlet-class> 
     
     <init-param> 
          <param-name>servlet-class</param-name> 
          <param-value>com.liferay.portal.jsonwebservice.JSONWebServiceServlet</param-value> 
         </init-param> 
         <load-on-startup>0</load-on-startup> 
      
  </servlet> 
      
  <servlet-mapping> 
         <servlet-name>JSON Web Service
  Servlet</servlet-name> 
         <url-pattern>/api/jsonws/*</url-pattern> 
      
  </servlet-mapping> 
            <jsp-config> 
                        <taglib> 
                                    <taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri> 
                                    <taglib-location> 
                                                /WEB-INF/tld/liferay-portlet.tld 
                                    </taglib-location> 
                        </taglib> 
                        <taglib> 
                                    <taglib-uri>http://liferay.com/tld/aui</taglib-uri> 
                                    <taglib-location>/WEB-INF/tld/aui.tld</taglib-location> 
                        </taglib> 
            </jsp-config> 
</web-app> | 
Step: 4
Run service builder using ant
build-service or in eclipse you can run this from ant view.
Step: 5
Writing Custom methods for produce JSON data
We need to decide for which entity we have to provide custom JSON services
.find appropriate entity and write method XXXServiceImpl.java
this is under package of
 you-base-package.service.impl package of your source.
Here XXX is entity name which is specified in service.xml
In our example I have
implemented in EmployeeServiceImpl.java
here I am getting employee object by employeeId. This method return employee
object. In liferay any object automatically sterilizes and produces as JSON
data.
The following is example for code
| 
public class EmployeeServiceImpl extends
  EmployeeServiceBaseImpl {     
            public  com.meera.jsonwebservices.db.model.Employee
  getEmployee( 
                                    long
  emplyeeId) 
                                    throws
  com.liferay.portal.kernel.exception.PortalException, 
                                                com.liferay.portal.kernel.exception.SystemException
  { 
                                    return
  EmployeeLocalServiceUtil.getEmployee(emplyeeId); 
                        } 
} | 
Once we completed writing custom method in XXXServiceImpl.java 
Then we need to run service builder using ant build-service command or from eclipse ant view you can
run same command
Step: 6
Now finally deploy the portlet into server by using ant deploy command or from ant view you can use same command
Now we are ready with custom JSON web services
Note: 
For each modification in XXXServiceImpl.java or in service layed we have
run ant build-service command  later we have to deploy the portlet using ant deploy then only change will be
applied to the services.
Accessing JSON web
services
To access the services we need to use following URL pattern
Server:
 It’s your domain name or host name
if you are in local the its “localhost”
Port: 
It’s your application server port number. 
plugin-context:
 it’s our plug-in portlet context
name its simple as portlet name
api/jsonws: 
This is path for call JSON Web Service servlet this is configured
in web.xml
service-class-name: 
 service-class-name is generated
from the service’s class name by removing the Service or ServiceImpl
suffix and making it lower case.This is our service class name where we
implemented custom method or its simple a entity name which is in service.xml. In our example we
implemented our method in EmployeeServiceImpl.java
Finally we have to use in URL as employee
when we observe it’s just entity name in service.xml
service-method-name: 
Service-method-name is generated from the service’s method name by converting
its camel case to lower case and using dashes (-) to separate words
Finally our Complete URL
like this for our Example:
| 
Plugin context path | 
CustomJsonWebservices-portlet | 
| 
Web service servelet path | 
/api/jsonws | 
| 
Service Class Name | 
EmployeeServiceImpl.java
  converted as employee | 
| 
Service Method Name | 
getEmplyee(--)
  converted as get-employee | 
Passing parameters and
its values:
We can pass parameters in two ways
Query String
URL pattern and separated
param name and value by slash(/)
Complete URL example with
query string
Complete URL by URL
pattern:
For Our Example Complete URL to access employee data by passing employee
id is following like this
| 
OR 
result: {"employeeDesignation":"SoftwareEngineer","emplyeeId":1,"emplyeeName":"meera"} | 
Note:
 Some time its ask Authentication so
we should pass admin credentials as URL headers
With authentication The URL like follow
| 
OR 
result: {"employeeDesignation":"SoftwareEngineer","emplyeeId":1,"emplyeeName":"meera"} | 
Note:
 All these URLs you can use from any browser and see the JSON data.
Here sometimes browsers not allows @ or # symbols in URL then we have to make
this as URL encoding type characters
For encode URL and test in browse use following link and encode
Encoded URL:
| 
OR | 
Well as of now we just done created Custom service and its calling
Now we will see another way to call same web service method in JSON Web Services Invoker
JSON web service Invoker:
JSON Web Services Invoker is one of the mechanism to call some complex web
services very easy way.
Here we can call JSON web service Invoker by following URL pattern
URL explanation is same like i explained previous section here we need to remember
is to call invoker we have to use path /api/jsonws/invoke
This call take only one parameter i.e. cmd the value of this parameter is JSON Map.
Here we need to pass parameter as query string only like follow
Our complete URL for
example is
What is JSON Map?
JSON Map is simple JSON object it contains key and value here value is
another JSON object which contains key and value
In JSON map key will be used as service
call path and value is parameters
which passing to service calls.
The same example we discussed above we can do like this
Take the example get
employee data by passing id.
Our Normal URL call is as follows
In above URL service call is   
employee/get-employee/  and
parameter is employeeId and its value is 1
Now the following is JSON
map for above
| 
{ 
"/employee/get-employee":
  { 
"emplyeeId": 1, 
} 
} | 
Here key is used as Service call and value is another json object contains
parameters and its value.
Now call our complete web service call using JSON web service Invoker as
follows
| 
result:  
{"employeeDesignation":"Software
  Engineer", "emplyeeId":1,"emplyeeName":"meera"} | 
This is way we have to pass JSON map to JSON web service invoker.
We can assign data as some reference object like following .here we have
to specify $ before variable
| 
{ 
"$emp=/employee/get-employee":
  { 
"emplyeeId": 1, 
} 
} | 
$emp is reference variable
|  | 
In above call we will get JSON data have all columns of Employee Table
Fetching required columns from JSON Web service invoker means filtering columns
| 
{ 
"$emp[emplyeeName,emplyeeId]=/employee/get-employee":
   
{ 
"emplyeeId": 1, 
} 
} | 
The following is complete web service call to filter columns using JSON
web service invoker
| 
result: {"emplyeeId":1,"emplyeeName":"meera"} | 
As of now we just call custom web service which is related to one entity
or one table
Now we will see how to fetch JSON data so that data comes from multiple
Tables
Some times in real requirement the data should fetch from multiple tables.
To make use of custom method we can produce JSON web services so that data
come from multiple tables.
Understanding Real Scenario:
I have one employee each employee have multiple addresses.
Here I have two tables Employee
and Address tables.
If we generate JSON web services from liferay it will serve only one table
data for service. But here data stored in two tables.
So now we have to produce JSON services so that data should come from Employee Tables and Address table
Employee Table:
| 
employeeId | 
employeeName | 
employeeDesignation | 
| 
1 | 
meera | 
Software Engineer | 
| 
2 | 
prince | 
Architect | 
| 
3 | 
savvy | 
Developer | 
Address Table:
| 
Id | 
emplyeeId | 
Address | 
| 
1 | 
1 | 
Hyderabad | 
| 
2 | 
1 | 
Hong Kong | 
| 
2 | 
1 | 
Landon | 
When you observe above data employee meera have 3 addresses
This is where we need to apply custom JSON web services.
Assume my data should be like as followed structure
| 
{ 
        name:”meera”, 
       addresess:[ 
                          “Hyderabad”,”Landon”,”Hong
  Kong” 
                        ] 
} | 
We have two options 
Complete manual
preparation of JSON data 
Use JSON Web service
Invoker Nested calls
Complete manual
preparation of JSON data:
In the manual preparation
we will prepare JSON structure and will produce data.
In general List and any java object type can be serialize and will be
produces as JSON data in liferay web services.Some scenarios some complex object
will not be sterilize.If some thing complex structure then we have to prepare JSON
data and we will produce as web services.
Default sterilization for
list type and any object type: 
In this scenario when we return some java object in custom method it will
be automatically converted as JSON data. Here we need not do like this 
Example for  Java Object to JSON data or JSON Object:
| public class EmployeeServiceImpl extends EmployeeServiceBaseImpl { 
            public  com.meera.jsonwebservices.db.model.Employee
  getEmployee( 
                                    long
  emplyeeId) 
                                    throws
  com.liferay.portal.kernel.exception.PortalException, 
                                                com.liferay.portal.kernel.exception.SystemException
  { 
                                    return
  EmployeeLocalServiceUtil.getEmployee(emplyeeId); 
                        } 
} | 
In above custom method getEmplyee
return Employee objects type. Here
we need not to serialize the data and it will be converted as JSON data by default
this is default behavior of liferay web services.
The following is URL to
access method
| 
OR 
result: {"employeeDesignation":"Software Engineer","emplyeeId":1,"emplyeeName":"meera"} | 
Note:
In the above custom method return Employee object but finally object convereted as JSON data.
In the above custom method return Employee object but finally object convereted as JSON data.
 Example for  List to JSON data
| public class AddressServiceImpl extends AddressServiceBaseImpl { 
            public 
  List<com.meera.jsonwebservices.db.model.Address> getAddressList(long
  emplyeeId) 
                                    throws
  com.liferay.portal.kernel.exception.PortalException, 
                                                com.liferay.portal.kernel.exception.SystemException
  { 
                                    return
  AddressUtil.findByemplyeeId(emplyeeId); 
                        } 
} | 
In the above custom method return list of Address objects for particular employee
id.
Here list will be converted as JSON data by default
The following is URL to
call the above service
| 
OR 
result: [{"employeeAddress":"Hyderabad","emplyeeId":1,"id":1},{"employeeAddress":"Hong Kong","emplyeeId":1,"id":2}] | 
Here Address is our service
class and getAddressList is custom
method to give list of address objects for particular employee.
Here List will be converted as JSON array simple.
Some scenarios which data is complex then default sterilization not work
all times when default sterilization not work then we will prepare JSON data
manually in custom method. Scenarios like list have map objects and map have
list objects.
Example for specialized structure:
Take our previous scenario one employee have many address but my data
structure should be like follows
| 
{ 
        name:”meera”, 
       addresess:[ 
                          “Hyderabad”,”Landon”,”Hong
  Kong” 
                        ] 
} | 
We can’t produce this same JSON data by default here we have to prepare JSON
data manually from java objects.
The following is Example:
| public class EmployeeServiceImpl extends EmployeeServiceBaseImpl { 
            public  JSONObject getEmployeeManualJsonData( 
                                    long
  emplyeeId) 
                                    throws
  com.liferay.portal.kernel.exception.PortalException, 
                                                com.liferay.portal.kernel.exception.SystemException
  { 
                        JSONObject
  employeeData=JSONFactoryUtil.createJSONObject(); 
                        JSONArray
  addressArray=JSONFactoryUtil.createJSONArray(); 
                        Employee
       empObject=EmployeeLocalServiceUtil.getEmployee(emplyeeId); 
                        employeeData.put("name",empObject.getEmplyeeName()); 
                        for(Address
  empaddress:AddressUtil.findByemplyeeId(emplyeeId)){ 
                                    addressArray.put(empaddress.getEmployeeAddress()); 
                        } 
                        employeeData.put("addresess",
  addressArray); 
                                    return
  employeeData; 
                        } 
} | 
Here service class is EmployeeServiceImpl.java it will be converts as employee in URL and method is getEmployeeManualJsonData
it will be converted in URL as get-employee-manual-json-data
The following is URL to
access above service
| 
OR 
result: {"name":"meera","addresess":["Hyderabad","Hong Kong","Landon"]} | 
Note:
 liferay providing JSONFactoryUtil class from this
we can create JSONArray and JSONObject.
By using above classes we can prepare JSON data manually in custom web
service method.
Nested JSON web service
Invoker:
We already know JSON Web service Invoker is one of the way to call web
services in liferay.
Nested JSON web service invoker has ability serve data from multiple tables.
By using this we can get data from multiple tables which are related to
each other.
Same above scenarios I want data fetch all addresses for employee by pass
employeeId.
We can call following web service invoker to get employee address. From
nested web service invoker we can achieve that.
The following is JSON map for fetch employee addresses
| 
{ 
"$employee
  =/employee/get-employee":  
{ 
"emplyeeId": 1, 
"$address =
  /address/get-address-list": { 
"@emplyeeId" :
  "$employee.emplyeeId" 
} 
 } 
} | 
@emplyeeId  at which parameter we pass to service call
$employee.emplyeeId   we will get employeeId from $employee reference object.
emplyeeId is same as column name  of
entity which we mention in service.xml.
Observer above JSON Map:
First we need to fetch employee object and referenced by variable called $employee we use this employee object
to get employeeId and this id will
be passed to /address/get-address-list
service call.
In the first service call i.e. /employee/get-employee   we
will get employee object and referenced by variable, in the next service call i.e. /address/get-address-list we use this
reference variable to get employeeId
and that will passed as parameter value.
Here we are calling two service calls within one JSON Map object that is why
we call it as Nested JSON Web Service Invoker.
Note:
Here all parameters which we passed
in JSON map should be same as parameter names which we used in custom method
implementation in XXXServiceImpl
class.
The final web service
call using Nested JSON web service invoke 
| 
result: {"emplyeeId":1,"address":[{"employeeAddress":"Hyderabad","emplyeeId":1,"id":1},{"employeeAddress":"Hong Kong","emplyeeId":1,"id":2},{"employeeAddress":"Landon","emplyeeId":1,"id":3}],"emplyeeName":"meera","employeeDesignation":"Software Engineer"} | 
Filter columns in Nested
JSON web service call
| 
result: {"emplyeeId":1,"address":[{"employeeAddress":"Hyderabad","emplyeeId":1,"id":1},{"employeeAddress":"Hong Kong","emplyeeId":1,"id":2},{"employeeAddress":"Landon","emplyeeId":1,"id":3}],"emplyeeName":"meera"} | 
In the above call we only get employeeId
and employeeName from employee
object.
Now calling JSON web
service with portal context:
As of now we have used plugin portlet context for calling web services. We
can also call web services using portal context/
The following is pattern
to call from portal context:
.
|  | 
Note:
Conveniently, requests sent this way can leverage the user’s
authentication in his current portal session. Liferay’s JavaScript API for
services calls plugin services using this method.
The following is call web
service from plugin context.
Note:
This calls the plugin’s service in a separate web application that is not
aware of the user’s current session in the portal. As a result, accessing the
service in this manner requires additional authentication. You might use this
for batch services or other requests that don’t require context.
The following are
dependent properties related to JSON web service in liferay
| 
jsonws.web.service.invalid.http.methods=DELETE,POST,PUT 
jsonws.web.service.strict.http.method=true 
json.service.auth.token.enabled=true 
json.service.auth.token.hosts.allowed=255.255.255.255 
json.deserializer.strict.mode=false 
jsonws.web.service.public.methods=* | 
Note: 
Please consider all above properties in your portal.properties file. If something
you  want change you can use
portal-ext.properties file to override.
Important points:
- Liferay provides two kinds of web services SOAP and REST.
- JSON web services is part REST bases web services which partially follows rest specifications.
- To implement service layer in liferay we will use service builder to and if we use remote- service is true then we can get data base services and JSON web services.
- Liferay web services serve only one table data by default.
- If we want get data which is related multiple tables or some specialize requirement we have to implement customer web services.
- To implement any custom services we will use XXXServiceImpl.java class.
- We can access JSON web services from simple URL pattern URL include plugin context, service class name, service method name and its parameters used by service method.
- We can pass parameter as query string or normal URL pattern so that each param and values should be separated by slash (/)
- We can access JSON web services using plug-in portlet context and portal context too. But difference is when we call from plug-in context we need implement our own authentication mechanism for services. If we use portal context then it will use authentication mechanism which provided by liferay portal.
- JSON web service invoker is way to call web services which will fetch data from multiple tables.
- To fetch data from multiple tables we have to implement custom method so that custom method prepares JSON data manually or we can use Nested JSON web service invoker.
- By default all java objects, list and map can be sterilize automatically and it will be produced as JSON data. Some scenarios if data has complex structure then we have to prepare JSON data manually.
- To prepare JSON data manually we can JSONFcatoryUtil class this can create JSONObject and JSONArray.
Screen 1:
The following screen depicts call JSON web services in browser and result
will be JSON data.
Note:
 In the URL host name and port number change according to you
environment and in the web service URL pass your liferay admin username and
password.
Reference Links:
 
 
 
 Posts
Posts
 
 
