Liferay IPC with Events

IPC Event는 Portlet 간의 IPC를 만드는 하나의 방법이다. Portlet들은 포털의 같은 페이지이거나 다른 페이지에 있어도 된다.

통신하는 두 Portlet이 있을 때 하나는 Event Producer Portlet, 다른 하나는 Event Listener Portlet으로 나뉜다. Producer가 어떤 데이터를 보내면 Listener는 데이터를 받아 이후의 작업을 실행한다.

여기서는 하나의 Producer, 여러개의 Consumer (Listener) portlet으로 가정한다. Producer는 event를 generate, Listener는 이 event를 receive 하는 것으로 생각하면 편하다.

IPC 시나리오

-Producer portlet에서 user email address을 보내면 Listener portlet에서 받아 user에 대한 full detail을 보여준다.

구현 절차

  1. portal-ext.properties의 portlet.event.distribution=layout-set으로 변경

    • 다른 페이지의 portlet 간에도 통신이 가능하도록 함.
  2. Producer portlet의 portlet.xml에 event definition을 정의.

    • 이 portlet이 producer portlet임을 정의
      <portlet>
      <supported-publishing-event xmlns:event="http://www.liferaysavvy.com">
      <qname>event:userEmailAddress</qname>
      </supported-publishing-event> 
      </portlet>
      <event-definition xmlns:event="http://www.liferaysavvy.com">
      <qname>event:userEmailAddress</qname>
      <value-type>java.lang.String</value-type>
      </event-definition>
      
  1. Producer portlet에 event generate

    public void getData(ActionRequest actionRequest, ActionResponse actionResponse){
    String userEmailAddress = ParamUtil.getString(actionRequest, "userEmailAddress");
    javax.xml.namespace.QName qName = new javax.xml.namespace.QName("http://www.liferaysavvy.com", "userEmailAddress"
    , "event");
    actionResponse.setEvent(qName, userEmailAddress);
    }
    
  2. portlet.xml Listener portlet even processing configuration 정의

    <portlet>
    <supported-processing-event xmlns:event="http:\/\/www.liferaysavvy.com">
    <qname>event:userEmailAddress<\/qname>
    <\/supported-processing-event>
    <\/portlet>

  3. Listener portlet에 event 처리하는 코드 삽입

(완성 코드는 IPCevents-portlet 참고)

IPC with Portlet Sessions

각 포틀릿은 포틀릿마다의 세션을 가지고 있다. 이것을 Portlet Session이라고 부르고 각 Session data는 다른 Portlet들과 공유되지 않는다. IPC를 위해 포틀릿 세션을 Public으로 만듦으로써 다른 포틀릿들과 데이터를 공유하게 된다.

STEP 1. Make Portlet session as public (liferay-portlet.xml)

<private-session-attributes>false</private-session-attributes>

STEP 2. Set some value in Porlet session that it will be accessd by other portlet.

doView, processAction, Custom action method에서 공유할 value를 지정해줘야한다.

Receiver portlet에서는 rendering 시에 이 값에 접근한다.

주의할 점은 Portlet session scope는 Application scope여야 한다는 것이다. 그래서 값만 다른 portlet에서 이용가능하도록 해야한다.

public void doView(...){
    String emailAddress = ParamUtil.getString(renderReqeust, "inputEmailAddress");
    PortletSession portletSession = renderRequest.getPortletSession();
    portletSession.setAttribute("emailAddress", emailAddress, PortletSession.APPLICATION_SCOPE);

or

public void processAction(...) {
    String emailAddress = ParamUtil.getString(actionReqeust, "inputEmailAddress");
    PortletSession portletSession = actionRequest.getPortletSession();
    portletSession.setAttribute("emailAddress", emailAddress, PortletSession.APPLICATION_SCOPE);

STEP 3. Receiver portlet에서 값을 가져오기. 주의할 것은 Sender portlet의 session과 같은 scope여야 함.

PortletSession portletSession = renderRequest.getPortletSession();
String emailAddress = (String) portletSession.getAttribute("emailAddress", PortletSession.APPLICATION_SCOPE);

IPC with Public Render Parameters

Specific parameter를 정의하고, 해당 parameter를 정의한 다른 포틀릿에서 데이터를 받아서 이용가능하도록 하는 방법.

포틀릿은 같은 페이지이거나 다른 페이지에 있어도 된다.

STEP 1. portal-ext.properties file의 값 변경 (liferay home directory에 존재하는 파일)

portlet.public.render.parameter.distribution=layout-set

이 property의 기본값은 "layout"인데 이 경우에는 같은 페이지 안에 있는 포틀릿 간에만 동작한다.

※ portal-ext.properties file에 대한 설명

STEP 2. Sender portlet의 portlet.xml 파일에 public render parameter 정의

<portlet-app>
<portlet>
...
<support-public-render-parameter>userEmailAddress</support-public-render-paramter>
...
</portlet>
<public-render-parameter>
<identifier>userEmailAddress</identifier>
<qname xmlns:x="http://liferaysavvy.com/userEmailAddress">x:userEmailAddress</qname>
</public-render-parameter>
</portlet-app>

STEP 3. Sender portlet의 processAction or Custom Action method에 Public render parameter 값 설정

public void getData(...) {
    String userEmailAddress = ParamUtil.getString(actionRequest, "userEmailAddress");
    actionResponse.setRenderParameter("userEmailAddress", userEmailAddress);
}

STEP 4. Receiver portlet에서 public render parameter 정의하고(portlet.xml), 값 받아오기

정의하는 부분은 STEP 2와 같으므로 생략.

// view.jsp
String userEmailAddress = ParamUtil.getString(renderRequest, "userEmailAddress", null);

// remove public render parameter from portlet
renderResponse.removePublicRenderParameter("userEmailAddress");

IPC with Client-side Ajax

같은 페이지 내에 있는 포틀릿 간에만 가능.

Sender Portlet은 event를 트리거하는, 즉 메시지를 다른 포틀릿에게 보내는 포틀릿이다.

Receiver Portlet은 event를 받는, Sender의 메시지에 반응하는 포틀릿이다. 1대 다 관계가 가능하다.

STEP 1. Sender portlet에서 event 등록

Liferay.fire('eventName', {
    param1:paramValue1,
    param2:paramValue2
});

// Real example
Liferay.fire('getUserData', {
    name: Jaesung Kim
});

STEP 2. Receiver portlet에서 event receive

Liferay.on('eventName', function(event) {
    // write code to get the values that sent by sender portlet
});

// Real example
Liferay.on('getUserData', function(event) {
    alert('User Name:' + event.name)
});

※ liferay-portlet.xml에서 <requires-namespaced-parameters/>값을 false로 하든지, <portlet-namespace />를 붙이든지 해야된다.

※ liferay java script implementation method -> Lifeary.fire(), LIferay.on() 등등

Sender portlet view.jsp 예제

<portlet:resourceURL var="getUserData"></portlet:resourceURL>
<script>
$(document).on('ready', function() {
    jQuery('#<portlet:namespace/>getUserByEmail').click(function(event) {
        var emailAddressValue = jQuery('#<portlet:namespace/>emailAddress').val();
        $.ajax({
            url:'<%=getUserData%>',
            dataType: "json",
            data: {emailAddress:emailAddressValue,
                    companyId:'<%=themeDisplay.getCompanyId()%>'
            },
            type: "get",
            success: function(data) {
                Liferay.fire('getUserData', {userData:data});
            },
            beforeSend: function() {

            },
            complete: function() {

            },
            error: function() {

            }
        });
    });
});
</script>
<aui:form method="POST" action="<%=getUserData%>">
    <aui:input type="text" name="emailAddress"id="emailAddress" label="Email Address"/>
    <aui:button type="button" name="getUserByEmail" value="Send" id="getUserByEmail" />
</aui:form>

-> 입력 form으로부터 emailAddress 값과 getUserByEmail 값을 가져온다. 가져올 때 jQuery 객체 부분에서 #<portlet:namespace/>를 붙여준게 특징. 그렇게 입력 받은 데이터로 ajax call을 통해 Sender의 serveResource method에 emailAddress와 company Id가 담긴 data를 보낸다. Ajax call의 결과를 받으면 (success 시) receiver portlet으로 Ajax call (Liferay.fire)을 이용한 IPC를 트리거한다.

Receiver Portlet view.jsp 예제

<script>
Liferay.on('getUserData', function(event) {
    jQuery('#userInformation').empty();
    jQuery('#errorInformation').empty();
    if(event.userData.error != null) {
        jQuery('#errorInformation').html(event.userData.error);
    }
    else {
        var htmlString="<table id='userData'>" +
            "<tr><td>User Id</td><td>"+event.userData.userId+"</td></tr>" +
            "<tr><td>First Name</td><td>"+event.userData.firstName+"</td></tr>" +
            "<tr><td>Last Name</td><td>"+event.userData.lastName+"</td></tr>" +
            "<tr><td>Email Address</td><td>"+event.userData.emailAddress+"</td></tr>" +
            "</table>";
        jQuery('#userInformation').html(htmlString);
    }
});
</script>
<div id="userInformation"></div>
<div id="errorInformation" style="color:red;font-weight:bold;"></div>

results matching ""

    No results matching ""