You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

portal-liferay-ipc.asciidoc 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. ---
  2. title: Vaadin IPC for Liferay
  3. order: 6
  4. layout: page
  5. ---
  6. [[portal.liferay-ipc]]
  7. = Vaadin IPC for Liferay
  8. ((("IPC add-on", id="term.portal.liferay-ipc", range="startofrange")))
  9. Portlets rarely live alone. A page can contain multiple portlets and when the
  10. user interacts with one portlet, you may need to have the other portlets react
  11. to the change immediately. This is not normally possible with Vaadin portlets,
  12. as Vaadin applications need to get an Ajax request from the client-side to
  13. change their user interface. On the other hand, the regular inter-portlet
  14. communication (IPC) mechanism in Portlet 2.0 Specification requires a complete
  15. page reload, but that is not appropriate with Vaadin or in general Ajax
  16. applications, which do not require a page reload. One solution is to communicate
  17. between the portlets on the server-side and then use a server-push mechanism to
  18. update the client-side.
  19. The Vaadin IPC for Liferay Add-on takes another approach by communicating
  20. between the portlets through the client-side. Events (messages) are sent through
  21. the [classname]#LiferayIPC# component and the client-side widget relays them to
  22. the other portlets, as illustrated in
  23. <<figure.portal.liferay-ipc.architecture>>.
  24. [[figure.portal.liferay-ipc.architecture]]
  25. .Vaadin IPC for Liferay Architecture
  26. image::img/liferay-ipc-architecture-hi.png[]
  27. Vaadin IPC for Liferay uses the Liferay JavaScript event API for client-side
  28. inter-portlet communication, so you can communicate just as easily with other
  29. Liferay portlets.
  30. Notice that you can use this communication only between portlets on the same
  31. page.
  32. <<figure.portal.liferay-ipc.demo>> shows Vaadin IPC for Liferay in action.
  33. Entering a new item in one portlet is updated interactively in the other.
  34. [[figure.portal.liferay-ipc.demo]]
  35. .Vaadin IPC Add-on Demo with Two Portlets
  36. image::img/liferay-ipc-demo-annotated-lo.png[]
  37. [[portal.liferay-ipc.installation]]
  38. == Installing the Add-on
  39. The Vaadin IPC for Liferay add-on is available from the Vaadin Directory as well
  40. as from a Maven repository. To download the installation package or find out the
  41. Maven or Ivy dependency, see the
  42. link:https://vaadin.com/directory#addon/vaadin-ipc-for-liferay[add-on page at
  43. Vaadin Directory], and install the add-on as described in
  44. <<../addons/addons-overview.asciidoc#addons.overview,"Using
  45. Vaadin Add-ons">>.
  46. The contents of the installation package are as follows:
  47. [filename]#vaadin-ipc-for-liferay-x.x.x.jar#:: The add-on JAR in the installation package must be installed in the [filename]#WEB-INF/lib# directory under the root context. The location depends on the server - for example in Liferay running in Tomcat it is located under the [filename]#webapps/ROOT# folder of the server.
  48. [filename]#doc#:: The documentation folder includes a [filename]#README.TXT# file that describes the contents of the installation package briefly, and [filename]#licensing.txt# and [filename]#license-asl-2.0.txt#, which describe the licensing under the Apache License 2.0. Under the [filename]#doc/api# folder is included the complete JavaDoc API documentation for the add-on.
  49. [filename]#vaadin-ipc-for-liferay-x.x.x-demo.war#:: A WAR containing demo portlets. After installing the add-on library and compiling the widget set, as described below, you can deploy the WAR to Liferay and add the two demo portlets to a page, as shown in <<figure.portal.liferay-ipc.demo>>. The source of the demo is available at link:http://dev.vaadin.com/svn/addons/IPCforLiferay/trunk/demo/src/com/vaadin/addon/ipcforliferay/demo/[dev.vaadin.com/svn/addons/IPCforLiferay/trunk/].
  50. The add-on contains a widget set, which you must compile into the Vaadin widget
  51. set installed in the portal.
  52. [[portal.liferay-ipc.communication]]
  53. == Basic Communication
  54. [classname]#LiferayIPC# is an invisible user interface component that can be
  55. used to send messages between two or more Vaadin portlets. You add it to an
  56. application layout as you would any regular user interface component.
  57. ----
  58. LiferayIPC liferayipc = new LiferayIPC();
  59. layout.addComponent(liferayipc);
  60. ----
  61. You should be careful not to remove the invisible component from the portlet
  62. later if you modify the layout of the portlet.
  63. The component can be used both for sending and receiving messages, as described
  64. next.
  65. [[portal.liferay-ipc.communication.sending]]
  66. === Sending Events
  67. You can send an event (a message) with the [methodname]#sendEvent()# method,
  68. which takes an event ID and the message data as parameters. The event is
  69. broadcast to all listening portlets. The event ID is a string that can be used
  70. to identify the recipient of an event or the event type.
  71. ----
  72. liferayipc.sendEvent("hello", "This is Data");
  73. ----
  74. If you need to send more complex data, you need to format or serialize it to a
  75. string representation as described in <<portal.liferay-ipc.serialization>>.
  76. [[portal.liferay-ipc.communication.receiving]]
  77. === Receiving Events
  78. A portlet wishing to receive events (messages) from other portlets needs to
  79. register a listener in the component with [methodname]#addListener()#. The
  80. listener receives the messages in a [classname]#LiferayIPCEvent# object.
  81. Filtering events by the ID is built in into the listener handler, you give the
  82. listened event ID as the first parameter for the [methodname]#addListener()#.
  83. The actual message data is held in the [parameter]#data# property, which you can
  84. read with [methodname]#getData()#.
  85. ----
  86. liferayipc.addListener("hello", new LiferayIPCEventListener() {
  87. public void eventReceived(LiferayIPCEvent event) {
  88. // Do something with the message data
  89. String data = event.getData();
  90. Notification.show("Received hello: " + data);
  91. }
  92. });
  93. ----
  94. A listener added to a [classname]#LiferayIPC# can be removed with
  95. [methodname]#removeListener()#.
  96. [[portal.liferay-ipc.concerns]]
  97. == Considerations
  98. Both security and efficiency should be considered with inter-portlet
  99. communications when using the Vaadin IPC for Liferay.
  100. [[portal.liferay-ipc.concerns.security]]
  101. === Browser Security
  102. As the message data is passed through the client-side (browser), any code
  103. running in the browser has access to the data. You should be careful not to
  104. expose any security-critical data in client-side messaging. Also, malicious code
  105. running in the browser could alter or fake messages. Sanitization can help with
  106. the latter problem and encryption to solve the both issues. You can also share
  107. the sensitive data through session attributes or a database and use the
  108. client-side IPC only to notify that the data is available.
  109. [[portal.liferay-ipc.concerns.efficiency]]
  110. === Efficiency
  111. Sending data through the browser requires loading and sending it in HTTP
  112. requests. The data is held in the memory space of the browser, and handling
  113. large data in the client-side JavaScript code can take time. Noticeably large
  114. message data can therefore reduce the responsiveness of the application and
  115. could, in extreme cases, go over browser limits for memory consumption or
  116. JavaScript execution time.
  117. [[portal.liferay-ipc.attributes]]
  118. == Communication Through Session Attributes
  119. In many cases, such as when considering security or efficiency, it is better to
  120. pass the bulk data on the server-side and use the client-side IPC only for
  121. notifying the other portlet(s) that the data is available. Session attributes
  122. are a conveninent way of sharing data on the server-side. You can also share
  123. objects through them, not just strings.
  124. The session variables have a __scope__, which should be
  125. [parameter]#APPLICATION_SCOPE#. The "application" refers to the scope of the
  126. Java web application (WAR) that contains the portlets.
  127. If the communicating portlets are in the same Java web application (WAR), no
  128. special configuration is needed. You can also communicate between portlets in
  129. different WARs, in which case you need to disable the
  130. [parameter]#private-session-attributes# parameter in
  131. [filename]#liferay-portlet.xml# by setting it to [literal]#++false++#. Please
  132. see Liferay documentation for more information regarding the configuration.
  133. You can also share Java objects between the portlets in the same WAR, not just
  134. strings. If the portlets are in different WARs, they normally have different
  135. class loaders, which could cause incompatibilities, so you can only communicate
  136. with strings and any object data needs to be serialized.
  137. Session attributes are accessible through the [classname]#PortletSession#
  138. object, which you can access through the portlet context from the Vaadin
  139. [classname]#Application# class.
  140. ----
  141. Person person = new Person(firstname, lastname, age);
  142. ...
  143. PortletSession session =
  144. ((PortletApplicationContext2)getContext()).
  145. getPortletSession();
  146. // Share the object
  147. String key = "IPCDEMO_person";
  148. session.setAttribute(key, person,
  149. PortletSession.APPLICATION_SCOPE);
  150. // Notify that it's available
  151. liferayipc.sendEvent("ipc_demodata_available", key);
  152. ----
  153. You can then receive the attribute in a [classname]#LiferayIPCEventListener# as
  154. follows:
  155. ----
  156. public void eventReceived(LiferayIPCEvent event) {
  157. String key = event.getData();
  158. PortletSession session =
  159. ((PortletApplicationContext2)getContext()).
  160. getPortletSession();
  161. // Get the object reference
  162. Person person = (Person) session.getAttribute(key);
  163. // We can now use the object in our application
  164. BeanItem<Person> item = new BeanItem<Person> (person);
  165. form.setItemDataSource(item);
  166. }
  167. ----
  168. Notice that changes to a shared object bound to a user interface component are
  169. not updated automatically if it is changed in another portlet. The issue is the
  170. same as with double-binding in general.
  171. [[portal.liferay-ipc.serialization]]
  172. == Serializing and Encoding Data
  173. The IPC events support transmitting only plain strings, so if you have object or
  174. other non-string data, you need to format or serialize it to a string
  175. representation. For example, the demo application formats the trivial data model
  176. as a semicolon-separated list as follows:
  177. ----
  178. private void sendPersonViaClient(String firstName,
  179. String lastName, int age) {
  180. liferayIPC_1.sendEvent("newPerson", firstName + ";" +
  181. lastName + ";" + age);
  182. }
  183. ----
  184. You can use standard Java serialization for any classes that implement the
  185. [interfacename]#Serializable# interface. The transmitted data may not include
  186. any control characters, so you also need to encode the string, for example by
  187. using Base64 encoding.
  188. ----
  189. // Some serializable object
  190. MyBean mybean = new MyBean();
  191. ...
  192. // Serialize
  193. ByteArrayOutputStream baostr = new ByteArrayOutputStream();
  194. ObjectOutputStream oostr;
  195. try {
  196. oostr = new ObjectOutputStream(baostr);
  197. oostr.writeObject(mybean); // Serialize the object
  198. oostr.close();
  199. } catch (IOException e) {
  200. Notification.show("IO PAN!"); // Complain
  201. }
  202. // Encode
  203. BASE64Encoder encoder = new BASE64Encoder();
  204. String encoded = encoder.encode(baostr.toByteArray());
  205. // Send the IPC event to other portlet(s)
  206. liferayipc.sendEvent("mybeanforyou", encoded);
  207. ----
  208. You can then deserialize such a message at the receiving end as follows:
  209. ----
  210. public void eventReceived(LiferayIPCEvent event) {
  211. String encoded = event.getData();
  212. // Decode and deserialize it
  213. BASE64Decoder decoder = new BASE64Decoder();
  214. try {
  215. byte[] data = decoder.decodeBuffer(encoded);
  216. ObjectInputStream ois =
  217. new ObjectInputStream(
  218. new ByteArrayInputStream(data));
  219. // The deserialized bean
  220. MyBean deserialized = (MyBean) ois.readObject();
  221. ois.close();
  222. ... do something with the bean ...
  223. } catch (IOException e) {
  224. e.printStackTrace(); // Handle somehow
  225. } catch (ClassNotFoundException e) {
  226. e.printStackTrace(); // Handle somehow
  227. }
  228. }
  229. ----
  230. [[portal.liferay-ipc.nonvaadin]]
  231. == Communicating with Non-Vaadin Portlets
  232. You can use the Vaadin IPC for Liferay to communicate also between a Vaadin
  233. application and other portlets, such as JSP portlets. The add-on passes the
  234. events as regular Liferay JavaScript events. The demo WAR includes two JSP
  235. portlets that demonstrate the communication.
  236. When sending events from non-Vaadin portlet, fire the event using the JavaScript
  237. [methodname]#Liferay.fire()# method with an event ID and message. For example,
  238. in JSP you could have:
  239. ----
  240. <%@ taglib uri="http://java.sun.com/portlet_2_0"
  241. prefix="portlet" %>
  242. <portlet:defineObjects />
  243. <script>
  244. function send_message() {
  245. Liferay.fire('hello', "Hello, I'm here!");
  246. }
  247. </script>
  248. <input type="button" value="Send message"
  249. onclick="send_message()" />
  250. ----
  251. You can receive events using a Liferay JavaScript event handler. You define the
  252. handler with the [methodname]#on()# method in the Liferay object. It takes the
  253. event ID and a callback function as its parameters. Again in JSP you could have:
  254. ----
  255. <%@ taglib uri="http://java.sun.com/portlet_2_0"
  256. prefix="portlet" %>
  257. <portlet:defineObjects />
  258. <script>
  259. Liferay.on('hello', function(event, data) {
  260. alert("Hello: " + data);
  261. });
  262. </script>
  263. ----
  264. (((range="endofrange", startref="term.portal.liferay-ipc")))