Wednesday, December 3, 2014

Custom notifications implementation in liferay


Implementing Custom Notifications in a Portlet


Liferay custom notifications require a User Notification Handler class that turns the notification into a nice HTML fragment that is displayed to the user. Also Liferay wants us to define the notification types that our portlet or application is creating in a definition file upfront.

<portlet>
<portlet-name>test-example</portlet-name>
<icon>/icon.png</icon>
 <indexer-class>com.liferay.testexample.search.EmployeeSearchIndexer</indexer-class>
<user-notification-definitions>example-user-notification-definitions.xml</user-notification-definitions>
<user-notification-handler-class>com.example.notifications.ExampleUserNotificationHandler</user-notification-handler-class>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
<css-class-wrapper>test-example-portlet</css-class-wrapper>
</portlet>

So the first thing we need to do is to define the location of our class that extends BaseUserNotificationHandler class and definitions inside liferay-portlet.xml. This can be done in liferay-portlet.xml like this:

The important part is user-notification-definitions and user-notification-handler-class tags. Now we need to actually define our notification inside that example-user-notification-definitions.xml. This file should go into your docroot/WEB-INF/src folder. 
Here is the example-user-notification-definitions.xml :
<?xml version="1.0"?>
<!DOCTYPE user-notification-definitions PUBLIC "-//Liferay//DTD User Notification Definitions 6.2.0//EN" "http://www.liferay.com/dtd/liferay-user-notification-definitions_6_2_0.dtd">
<user-notification-definitions>
<definition>
<notification-type>${com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID}</notification-type>
<description>receive-a-notification-when-example-triggered</description>
<delivery-type>
<name>email</name>
                  <type>${com.liferay.portal.model.UserNotificationDeliveryConstants.TYPE_EMAIL}</type>
<default>false</default>
<modifiable>true</modifiable>
</delivery-type>
<delivery-type>
<name>website</name>
<type>${com.liferay.portal.model.UserNotificationDeliveryConstants.TYPE_WEBSITE}</type>
<default>true</default>
<modifiable>true</modifiable>
</delivery-type>
</definition>
</user-notification-definitions>

So in our example portlet class we can actually add a new notification for the user. We can do it by using UserNotificationEventLocalServiceUtil in either our service builder class or one of our portlet classes.
Here’s how to add notification event: In below we are adding a new employee data to employee persistence and so we are adding an event saying that new employee has added to the site users. So we have to send this notification event to all the site users by adding notification events to all.

employee =EmployeeLocalServiceUtil.addEmployee(employee);        
           
ServiceContext serviceContext = new ServiceContext();
serviceContext.setScopeGroupId(themeDisplay.getScopeGroupId());
           
JSONObject payloadJSON = JSONFactoryUtil.createJSONObject();
payloadJSON.put("userId", themeDisplay.getUserId());
payloadJSON.put("employeeId", employee.getEmpId());
payloadJSON.put("additionalData", "Your notification was added!");

 List<User> siteUsers=  UserLocalServiceUtil.getGroupUsers(themeDisplay.getScopeGroupId());
        
        
for(User siteUser : siteUsers){               UserNotificationEventLocalServiceUtil.addUserNotificationEvent(siteUser.getUserId(), com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID, new Date().getTime(), themeDisplay.getUserId(), payloadJSON.toString(), false, serviceContext);
            System.out.println("notification event adding to user : "+siteUser.getScreenName());
          }


So now that we have our notification inside the database we want to actually show it to the user. When we look at the dockbar our notification number gets increased so we can be pretty sure that the notification was added. When you attempt to actually look at the notification you will probably see a blank white box. We need the notification handler class to actually handle the display side of our notification. This current example also handles the behavior like providing Approve and Reject buttons right in our example notification so that our example user could perform an action straight from the dockbar notification.

Here is the class :  ExampleUserNotificationHandler.java

package com.example.notifications;

import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.notifications.BaseUserNotificationHandler;
import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.model.UserNotificationEvent;
import com.liferay.portal.service.ServiceContext;

import javax.portlet.ActionRequest;
import javax.portlet.PortletURL;
import javax.portlet.WindowState;

public class ExampleUserNotificationHandler extends BaseUserNotificationHandler{

      public static final String PORTLET_ID = "testexample_WAR_testexampleportlet";

      public ExampleUserNotificationHandler() {
            setPortletId(ExampleUserNotificationHandler.PORTLET_ID);
      }
     
      @Override
      protected String getBody(UserNotificationEvent userNotificationEvent,
                  ServiceContext serviceContext) throws Exception {
            JSONObject jsonObject= JSONFactoryUtil.createJSONObject(userNotificationEvent.getPayload());
           
            long employeeId = jsonObject.getLong("employeeId");

            String title = "A new Employee data has been added ";

            String bodyText = "";
           
            LiferayPortletResponse liferayPortletResponse = serviceContext.getLiferayPortletResponse();
           
            PortletURL confirmURL = liferayPortletResponse.createActionURL(com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID);
            confirmURL.setParameter(ActionRequest.ACTION_NAME, "doSomethingGood");
            confirmURL.setParameter("redirect", serviceContext.getLayoutFullURL());
            confirmURL.setParameter("employeeId", String.valueOf(employeeId));
            confirmURL.setParameter("userNotificationEventId", String.valueOf(userNotificationEvent.getUserNotificationEventId()));
            confirmURL.setWindowState(WindowState.NORMAL);
           
            PortletURL ignoreURL = liferayPortletResponse.createActionURL(com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID);
            ignoreURL.setParameter(ActionRequest.ACTION_NAME, "cancelForExample");
            ignoreURL.setParameter("redirect", serviceContext.getLayoutFullURL());
            ignoreURL.setParameter("employeeId", String.valueOf(employeeId));
            ignoreURL.setParameter("userNotificationEventId", String.valueOf(userNotificationEvent.getUserNotificationEventId()));
            ignoreURL.setWindowState(WindowState.NORMAL);
           
           
            String body = StringUtil.replace(getBodyTemplate(), new String[] {
                  "[$CONFIRM$]", "[$CONFIRM_URL$]", "[$IGNORE$]",
                  "[$IGNORE_URL$]", "[$TITLE$]", "[$BODY_TEXT$]" }, new String[] {
                  serviceContext.translate("approve"), confirmURL.toString(),
                  serviceContext.translate("reject"), ignoreURL.toString(),
                  title, bodyText });
     
      return body;
           
           
      }
     
      @Override
      protected String getLink(UserNotificationEvent userNotificationEvent,
                  ServiceContext serviceContext) throws Exception {
            JSONObject jsonObject= JSONFactoryUtil.createJSONObject(userNotificationEvent.getPayload());
           
            long employeeId = jsonObject.getLong("employeeId");
           
            LiferayPortletResponse liferayPortletResponse = serviceContext.getLiferayPortletResponse();
            PortletURL confirmURL = liferayPortletResponse.createRenderURL(com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID);
            confirmURL.setParameter("redirect", serviceContext.getLayoutFullURL());
            confirmURL.setParameter("employeeId", String.valueOf(employeeId));
            confirmURL.setParameter("userNotificationEventId", String.valueOf(userNotificationEvent.getUserNotificationEventId()));
            confirmURL.setWindowState(WindowState.NORMAL);
           
      return confirmURL.toString();
           
           
      }
      protected String getBodyTemplate() throws Exception {
            StringBundler sb = new StringBundler(5);
            sb.append("<div class=\"title\">[$TITLE$]</div><div ");
            sb.append("class=\"body\">[$BODY_TEXT$]<a class=\"btn btn-action ");
            sb.append("btn-success\" href=\"[$CONFIRM_URL$]\">[$CONFIRM$]</a>");
            sb.append("<a class=\"btn btn-action btn-warning\" href=\"");
            sb.append("[$IGNORE_URL$]\">[$IGNORE$]</a></div>");
            return sb.toString();
      }

           
}


com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID string that you use as your notification type has to match an actual portlet ID. So  I have passed the PORTLET_ID as “testexample_WAR_testexampleportlet” which was the portelt I am placing notifications.
Now our code works as like If any employee data is added in to the table a new notification will send to all site users and that notification will be displayed on the notification bar .
After adding new employee a notification will be displayed in the dock bar as given below:
We can see the notification number is increased in the above screen. Click on notification:
As we created the content “A new Employee data has been added with 2 buttons ‘Approve’ and ‘Reject’ is displaying on notification title and body. Once clicking on ‘Approve’ button means the notification has read by the user and decreases its count. And all the notifications will  be available in the “Notifications” portlet which was the market place portlet .

For approve and reject buttons the code we should write in our portlet controller class as given below: TestExample.java
package com.test.example;

import com.liferay.counter.service.CounterLocalServiceUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.model.User;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.service.UserNotificationEventLocalServiceUtil;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.testexample.model.Employee;
import com.liferay.testexample.service.EmployeeLocalServiceUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;

public class TestExample extends MVCPortlet {
               
                public void addEntity(ActionRequest request, ActionResponse response)
                                                throws Exception {
               
                                ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
                                Employee employee = EmployeeLocalServiceUtil.createEmployee(CounterLocalServiceUtil.increment(Employee.class.getName()));
                               
                                SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
                               
                                employee.setFirstName(ParamUtil.getString(request, "firstName"));
                                employee.setFullName(ParamUtil.getString(request, "fullName"));
                                employee.setAge(ParamUtil.getInteger(request, "age"));
                                employee.setJoinedDate(ParamUtil.getDate(request, "joinedDate", sdf));
                                employee.setGender(ParamUtil.getString(request, "gender"));
                               
                                employee.setCompanyId(themeDisplay.getCompanyId());
                                employee.setGroupId(themeDisplay.getScopeGroupId());
                                employee.setUserId(themeDisplay.getUserId());
                               
                                employee =EmployeeLocalServiceUtil.addEmployee(employee);                            
                               
                                ServiceContext serviceContext = new ServiceContext();
        serviceContext.setScopeGroupId(themeDisplay.getScopeGroupId());
                               
                                JSONObject payloadJSON = JSONFactoryUtil.createJSONObject();
                    payloadJSON.put("userId", themeDisplay.getUserId());
                    payloadJSON.put("employeeId", employee.getEmpId());
                    payloadJSON.put("additionalData", "Your notification was added!");
                   
                   
                    List<User> siteUsers=  UserLocalServiceUtil.getGroupUsers(themeDisplay.getScopeGroupId());
                  
                  
                    for(User siteUser : siteUsers){
                                UserNotificationEventLocalServiceUtil.addUserNotificationEvent(siteUser.getUserId(), com.example.notifications.ExampleUserNotificationHandler.PORTLET_ID, new Date().getTime(), themeDisplay.getUserId(), payloadJSON.toString(), false, serviceContext);
                                System.out.println("notification event adding to user : "+siteUser.getScreenName());
                    }
                                response.setRenderParameter("mvcPath","/html/testexample/view.jsp");
                                }
               
                public void doSomethingGood(ActionRequest request, ActionResponse response)
                                                throws IOException, PortletException {

                                ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
                                long groupId = themeDisplay.getScopeGroupId();
                                long employeeId = ParamUtil.getLong(request, "employeeId");
                                long userNotificationEventId = ParamUtil.getLong(request, "userNotificationEventId");
                                try {
                                                UserNotificationEventLocalServiceUtil.deleteUserNotificationEvent(userNotificationEventId);
                                               
                                } catch (PortalException e) {
                                                System.out.println("Failed to remove notification:"+e.getMessage());
                                } catch (SystemException e) {
                                                System.out.println("Failed to remove notification:"+e.getMessage());
                                }

                }
               
                public void cancelForExample(ActionRequest request, ActionResponse response)
                                                throws IOException, PortletException {

                                ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
                                long groupId = themeDisplay.getScopeGroupId();
                                long employeeId = ParamUtil.getLong(request, "employeeId");
                                long userNotificationEventId = ParamUtil.getLong(request, "userNotificationEventId");
                                try {
                                                UserNotificationEventLocalServiceUtil.deleteUserNotificationEvent(userNotificationEventId);
                                               
                                } catch (PortalException e) {
                                                System.out.println("Failed to remove notification:"+e.getMessage());
                                } catch (SystemException e) {
                                                System.out.println("Failed to remove notification:"+e.getMessage());
                                }
                }
               
                               
}

No comments:

Post a Comment