Liferay GWT portlet - replacing GWT-RPC with JSON
This is a continuation of my previous post Liferay GWT portlet - how to make it "instanceable" and use GWT RPC. The approach described there uses Liferay specific functionality called PortalDelegateServlet. This way one can easily use GWT RPC which somewhat simplifies client-server communication. However if you need to develop a JSR 286 portlet you need a more standard compatible way of doing AJAX calls. For this reason JSR 286 defines serverResource method and this post will show how to refactor the code to replace GWT RPC calls with exchanging JSON messages using serverResource method.
Let GWT know the prtlet URLs
First thing to do is to tell GWT what are the proper URLs to call the portlet. Therefore creating a Chatroom instance based on portlet id only, is no longer enough. To overcome this you need to provide a JavaScript object holding portlet URLs. I, for example, have called it ChatroomPortlet and it's defined in chatrooms.js file.
Then, in view.jsp, create and store that object instead of portlet id. Of course for the purpose of this example only resourceURL is needed but in a real world scenario you'll probably also need renderURL and actionURL. To map this JavaScript object to GWT class create JSNI class ChatroomJsObject.
Next you need to modify Chatroom's constructor to accept ChatroomJsObject instead of String representing portlet id. Of course this reflects how GWTEntryPoint creates Chatroom instances.
Have a look at my commit to see what has changed.
Create the JSR 286 portlet
Now you need to write a portlet and implement serveResource method. Basically the method contains the same logic that used to be in ChatroomServiceImpl. The only difference is that now it gets its input form JSON object and responds with JSON object. The portlet code is available here.
Of course don't forget to replace the default MVCPortlet with your own in portlet.xml
Again there is commit which does above modifications, so you can check what has changed.
Update GWT client-server calls
Having the portlet ready, it's time to change the GWT code to send and receive JSON to resourceURL instead of using GWT RPC. For this to work you need to add 2 GWT modules to Chatrooms.gwt.xml:
<inherits name="com.google.gwt.http.HTTP" />
<inherits name="com.google.gwt.json.JSON" />
To be able to convert JSON response to GWT class you'll have to provide another JSNI class ChatroomMessageJsObject. Finally the Chatroom class itself needs to be updated:
- replace the body of
sendMessageToServermethod to create JSON object and send it to the portlet bu using RequestBuilder - replace the body of
getMessagesmethod to covert JSON object from response to list of ChatroomMessageJsObject to be displayed. - convert
lastMessageTimeformDatetolongas there are some issues with passing dates in JSON
As usual you can refer to my commit to get an idea what and how has changed.
That's it. You are ready. Optionally you can do some cleanup by removing unused classes like I did.
Liferay multi-device extension
UPDATE: The extension described here targets Liferay 6.0. It was contributed to Liferay and is available out of the box since Liferay 6.1
Liferay - preserve GWT portlet state between reloads
One of the problems with GWT (which is even more noticeable in portal environment) is preserving it's state between page reloads. In a GWT-only application (or single portlet on the page case) one can give user no other option but using only GWT controls to practically avoid page reloads. In most cases however this is not really possible nor wise thing to do. In portlet environments in particular, reloading the page is a very commmon thing to do, giving all portlets a chance to refresh their content after some action has taken place. The thing is, GWT portlets will, by default, render their initial state, which may not be what user expects.