Pages

Wednesday 29 May 2013

How to create Friendly URL for Liferay portlet (ServeResource URL) Which will give a JSONFeed File as response .


How to create Friendly URL for Liferay portlet (ServeResource URL) Which will give a JSONFeed File as response .

My  goal in this article will be to show you how to shorten the URL in portlet so that its more user friendly.
Actually I have a requirement where I have written a ServerResource()   on a link of the portlet .Once User clicks on the link ,a Json feed file would popup as a download with SAVE or OPEN options.
Generally its similar to Web Services ,I will share a link(Lengthy) with client ,who can consume my feeds and who can share it with other teams .But I am not using any webservices here ,as I want it to be as simple as possible.
Note: There is no change on the state of the portlet , only a popup to save/open is showed.
Here is how I have done it.
I have used simple Liferay MVC portlet .
Where I have a Portlet Controller class as show below.

This is under a package com.client.nci.topstory.admin.controller
Now here the code for creating a Ajax link (serverResource)  inside view.jsp

<portlet:resourceURL var="jsonUrl"> </portlet:resourceURL>

<a href='<%=jsonUrl %>'>json feed link</a>
               


If you see the link Url ,i.e.
http://localhost:8080/web/guest/topicpage1?p_p_id=topstorytopicpage_WAR_NewTopStoryportlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&p_p_cacheability=cacheLevelPage&p_p_col_id=column-1&p_p_col_count=1

So when ever User clicks on the below link  a popup whould appear as show below
         

Here is my code in the portlet class .i.e. controller class (ServerResource())

/*
 * This is for passing Json File for outside Users
*/
 public void serveResource(ResourceRequest request, ResourceResponse response)
                throws PortletException, IOException {
         
                  

                   ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
               String portalUrl = themeDisplay.getPortalURL();
              
                    TopStoryAdminServiceImpl topStoryService = new TopStoryAdminServiceImpl();
                    
//service method call which will return me my JSON FEED
 Map<String,TopStoryAdminBean> topStoryMap = topStoryService.fetchHomePageTopStories(count,portalUrl);
String jsonMap ="";
                  
 // Json Conversion
jsonMap = topStoryService.buildJsonFeedString(topStoryMap);

//Logic to send responce as Json File  to User
                              
 response.setContentType("text/json");
 OutputStream outPut = response.getPortletOutputStream();
 outPut.write(jsonMap.getBytes());
                              
 outPut.flush();
             }


Hope everyone understood what I am trying to do out here.
Now the part from my business logic ,whats important is the URl link ,what I have shared with client ,is very lengthy and not user friendly to remember.

So I gone through some links which suggested me to use different Url redirect techniques .
But I liked Liferay’s User Friendly Urls concept ,as the link which is shared is to a  3rd party users and important thing here is I Don’t know in which page my portlet is place to handle the such  request.

So I achieved the solution as below
Created a simple xml file called  friendly-url-router.xml and placed it under same package where my portlet class is written.
NOTE: If you try to place this xml file under any other folder then Classes (any sub folders of classes) .It will throw an Class loader Exception..
         
         



Here is my friendly-url-router.xml

<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE routes PUBLIC "-//Liferay//DTD Friendly URL Routes 6.0.0//EN" "http://www.liferay.com/dtd/liferay-friendly-url-routes_6_0_0.dtd"> 
     
    <routes> 
           <route> 
<pattern>/json</pattern> 
<implicit-parameter name="p_p_id">topstorytopicpage_WAR_NewTopStoryportlet</implicit-parameter>  <implicit-parameter name="p_p_lifecycle">2</implicit-parameter> 
<implicit-parameter name="p_p_state">normal</implicit-parameter> 
<implicit-parameter name="p_p_mode">view</implicit-parameter> 
<implicit-parameter name="p_p_cacheability">cacheLevelPage</implicit-parameter> 
<implicit-parameter name="p_p_col_id">column-1</implicit-parameter> 
<implicit-parameter name="p_p_col_count">1</implicit-parameter> 
   </route> 
 </routes> 


If you note ,I have given all the above parameter values from the existing server resource Url i.e.

 will change to :  localhost:8080/web/guest/topicpage1/-/topstory-feed/json


Now you have defined your friendly Url xml , all you need to do is register it with your portlet ,by adding a small piece of code  in your liferay-portlet.xml file as shown below.


<portlet>
<portlet-name>topstorytopicpage</portlet-name>
<icon>/icon.png</icon>
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class> 
<friendly-url-mapping>topstory-feed</friendly-url-mapping> 
<friendly-url-routes>com/client/nci/topstory/admin/controller/friendly-url-router.xml</friendly-url-routes> 
………………….………….
………………………………….
</portlet>



NOTE: In the above two file I have marked <patter> and <friendly-url-mapping<friendly-url-mapping > RED in colour .

Because these to will merge and generate a Friendly URL  as shown below

/-/topstory-feed/json

Now this URL string when appended on any page of the portal ,will call your portlet serveResource() and generate a JSON Response file.

localhost:8080/web/guest/topicpage/-/topstory-feed/json
localhost:8080/web/guest/home/-/topstory-feed/json
You can try it on Any page .

That’s it ..
I have not gone in details about the parameter we have written in FriendlyURLRouter Xml file .If you wish you want to understand them here are the links I have gone through .