Thursday, May 29, 2014

Liferay Model Listeners

Introduction:

Liferay Model Listeners are event listeners which will be invoked when the changes made in Model Object.

Each model object can have its own model listener to listen changes in the model objects.

As for ORM concept any database interaction is mapped to java POJO object that is we can call it as Model Object.

Before perform any database interaction first we create or modify the model object then data will be stored or update in the tables.

In the ORM concept each table row we can treat as Model Object Instance that is called persistence object.

We can create our custom model listeners to existed models which are in portal through Hook Plugin.

We have different model classes in portal like User, Role, Group, Layout, Address, and Contact.

Apart from these we can also implement it for portlet level model class like DLFileEntry, JournalArticle and AssetEntry.

Note:

Before going implement model listener for any Model which are in portal or portlet level Please check in liferay if they are already existed or not. This you can search in portal.properties file the property prefix is value.object.listener.

If already there make sure keep existed business logic same and add your logic after that or create another model listener class and configure it with comma separate value for above property.

Example Properties for Model Listeners portal.properties


Pattern:

value.object.listeners.ActualModel Class Name=Our Custom Listener class Name


Model Listener to existed model objects which are in Portal level


value.object.listener.com.liferay.portal.model.Contact=
com.liferay.portal.model.ContactListener

value.object.listener.com.liferay.portal.model.Layout=
com.liferay.portal.model.LayoutListener,
com.liferay.portal.service.impl.LayoutSetPrototypeLayoutListener

value.object.listener.com.liferay.portal.model.LayoutSet=
com.liferay.portal.model.LayoutSetListener,
com.liferay.portal.service.impl.LayoutSetPrototypeLayoutSetListener

value.object.listener.com.liferay.portal.model.PortletPreferences=
com.liferay.portal.model.PortletPreferencesListener

value.object.listener.com.liferay.portal.model.User=
com.liferay.portal.model.UserListener

value.object.listener.com.liferay.portal.model.UserGroup=
com.liferay.portal.model.UserGroupListener


Note:

The above already existed in portal.properties file

Create Custom Model Listener to existed model object which are in portlet level.


value.object.listener.com.liferay.portal.model.Address=
com.meera.model.listeners.AddressListener

value.object.listener.com.liferay.portal.model.Contact=
com.meera.model.listeners.ContactListener

value.object.listener.com.liferay.portlet.documentlibrary.model.DLFileEntry=
com.meera.model.listeners.DLFileEntryListener


Note:

The overriding of portal properties can be done through Hook and we can use hook for existed models which are in liferay portal level and portlet related models.

So if want know changes in the above models we need create Model Listener and we can write some business logic to know all the changes made in model like ADD, DELETE and UPDATE.

Any Model Listener that should implement the ModelListener interface and it has some 
abstracted methods and we need to implement it.

The following are available methods in ModelListener interface


public interface ModelListener<T> {

public void onAfterAddAssociation(
Object classPK, String associationClassName,
Object associationClassPK)
throws ModelListenerException;

public void onAfterCreate(T model) throws ModelListenerException;

public void onAfterRemove(T model) throws ModelListenerException;

public void onAfterRemoveAssociation(
Object classPK, String associationClassName,
Object associationClassPK)
throws ModelListenerException;

public void onAfterUpdate(T model) throws ModelListenerException;

public void onBeforeAddAssociation(
Object classPK, String associationClassName,
Object associationClassPK)
throws ModelListenerException;

public void onBeforeCreate(T model) throws ModelListenerException;

public void onBeforeRemove(T model) throws ModelListenerException;

public void onBeforeRemoveAssociation(
Object classPK, String associationClassName,
Object associationClassPK)
throws ModelListenerException;

public void onBeforeUpdate(T model) throws ModelListenerException;

}


We have different named methods and these will be invoked based on action performed in Model Object.

Like if any data added in table respective model listener onAfterCreate(--) method will be invoked.

Similarly we have many methods based on action or change respective methods will be invokes on behalf of Model object.

Real time scenarios:

If any record add or delete for table based on this some tome we may need to delete or add other records such scenarios we can use model listeners.

To know more you can see source code in UserListener then we can understand importance of model listener.

If we want to track information in application then we will use Model Listeners for example if we want track document library information then we will create Model Listener for DLFileEntery then we can track all information with respect to Document Library.

We have two types of implementation
  1. Implement Model Listener for Existed Models
  2. Implement Model Listener for Plugin Portlet Models

Implement Model Listener for Existed Models

We will use hook to existed model which are in Portal Level or Portal Portlets Level.

Portal Level Models Examples:


Role, Group, Layout and Layoutset


Portlet Level Models Examples


DLFileEntry, Journal Articlle and AssetEntry


Steps: 1

Create Hook for Portal Properties

Step: 2

Add your Model Listener Implementation class name for your existed Model in hook portal properties file.

Step: 3

Implement Model Listener interface Methods in Model Listener Implementation class.

Note:

Model Listener should be thread safe that is why we have to implemented Message Bus concept to make it thread safe when concurrent actions performed in the model.

Message Bus:

Message bus is one of the concepts in liferay so that we can create some destinations and its respective listeners to send the information and perform further actions through its respective listeners.

Whenever any event is generated we will post information to configured destinations as soon as information posted in destination respective liters will be listening and will perform further activities.


Note:

service.properties file will be created after run the service-builder for the portlet.

One more important thing is when we re-run service builder then service.propertis file overridden with default properties file and make sure the property spring.config should have messaging-spring.xml path.

When you run service builder again need to add above file path in list of to spring-config property.

Assume we want Track Document Library Information

Create brand new liferay hook project for portal properties file.

Add following code in liferay-hook.xml file (/WEB-INF/liferay-hook.xml)

<hook>
       <portal-properties>portal.properties</portal-properties>
</hook>

Add following property in hook portal.properties file (/WEB-INF/src/portal.properties)


value.object.listener.com.liferay.portlet.documentlibrary.model.DLFileEntry=
com.meera.model.listeners.DLFileEntryListener


Implement Model Listener for DLFileEntry

We already know we need to implement all the methods which are present in the ModelListener interface and we need to implement in our Custom Model Listener class

Example Model Listener class as follows


package com.meera.model.listeners;
import com.liferay.portal.ModelListenerException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.model.BaseModelListener;
import com.liferay.portlet.documentlibrary.model.DLFileEntry;

public class DLFileEntryListener extends BaseModelListener<DLFileEntry> {
public void onBeforeCreate(DLFileEntry dlFileEntry) throws ModelListenerException {

_log.info("This method will be called before create document");

}

public void onBeforeRemove(DLFileEntry dlFileEntry) throws ModelListenerException {
_log.info("This method will be called before DELETE document");
}

public void onBeforeUpdate(DLFileEntry newDLFileEntry) throws ModelListenerException {
_log.info("This method will be called before UPDATE document");

}

private static Log _log =LogFactoryUtil.getLog(DLFileEntryListener.class);
}


Note:

When you use Document Library portlet then these methods will be called and you can information in log file or server console.

Implement Model Listener for Plugin Portlet Models

When we work with Plugin portlet some time we need create our own enmities in Plugin portlet and we may have our own model classes.

Whenever we want create model listener in Plugin portlet we will use service.properties file to configure our custom model listener on behalf of our model class.

Assume we have Student MVC Portlet and have Student Entity

Steps:

Create Liferay MVC Portlet

Create service builder and define your entity in service.xml

Run service builder then all service layer classes and its configuration files will be created.

In the service.properties file configure our custom model listener on behalf of our model class


com.meera.dbservice.model.StudentModel=
com.meera.model.listeners.StudentModelListener


Implement our model listener and that should implement the Model Listener interface

Example


package com.meera.model.listeners;
import com.liferay.portal.ModelListenerException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.model.BaseModelListener;
import com.liferay.portlet.documentlibrary.model.DLFileEntry;
public class StudentModelListener extends BaseModelListener<DLFileEntry> {
public void onBeforeCreate(DLFileEntry dlFileEntry) throws ModelListenerException {

_log.info("This method will be called before create Student");

}

public void onBeforeRemove(DLFileEntry dlFileEntry) throws ModelListenerException {
_log.info("This method will be called before DELETE Student");
}

public void onBeforeUpdate(DLFileEntry newDLFileEntry) throws ModelListenerException {
_log.info("This method will be called before UPDATE Student");

}

private static Log _log =LogFactoryUtil.getLog(DLFileEntryListener.class);
}


Portlet Development using Model Listeners

Assume we will find the information which is going on Document Library Portlet.

We need to implement model listener for DLFileEntry Model so that we can track all information.

Download Liferay Model Listener Example Portlet

https://sourceforge.net/projects/meeralferay/files/LiferayModelListenerPortlet/


Environment:


Liferay IDE 2.x+Eclipse (Kepler) +Liferay Plugins SDK 6.2+Tomcat 7.x Liferay Portal Bundle

Important Points

We have implemented DLFileEntry Model Leister to find information in Document Library Model class.

We have created Hook for the portlet and we configured model listener information in Hook portal.properties file.

For the storing information we have defined one entity in service.xml file

Once we run service builder to portlet then we will get required configuration files and java classes to perform CRUD operation on table.

We have used Message Bus destinations and it Listeners to post data and store the data in the table.

We have configured destinations and its listeners in messaging-spring.xml file which in /WEB-INF/src/META-INF/ directory.

We need to specify the messafing-config.xml file information in service.properties file which is in /WEB-INF/src/service.properties

service.properties file will be created after run the service builder and when we’re run service builder it will be revert back it default configuration so make sure for each re run service 
builder again add messaging-spring.xml information in service.propertires file.

Deployment and its Working.

Download portlet you can source or war file to deploy into liferay portal as your convenient.
Once portlet successfully deployed drag the portlet in any desired page. Portlet is available in sample category.

Now login as admin go to Document Library portlet add some documents and Update the documents.

Now come to our portlet and click on Document Library Records and you can see all information.

Similarly in the portlet we have document download page you can download any document again see the Document Library Records page you can see downloaded information.

Portlet Screens:

Default Page


Document download screen



Document Library Information Screen



Reference Links




Author

Wednesday, May 28, 2014

Liferay Audit Portlet and Hook

Introduction:

Liferay Audit is used to track many events and actions which are going in liferay portal.

Information like user login logout, document library files actions like add, delete and update .We will track all information using Liferay Audit portlets.

Liferay Audit Plugins consist of hook and portlet.

Hook is used to customize some classes and properties in the portal and portlet is used to track the data and show the information in control panel.


Download Portlet and Hook

These portlet and hook is available to only Liferay EE version. If you are an EE customer then downloads and deploy into your portal.

Download from market place


Conceptual Understanding:

Generally in application when we add some data or delete data from tables we will use persistence objects.

Once we fill the data in these objects then we will store into database this is called Hibernate Persistence logic.

So in any record or data going to add in the database it’s should use the POJO class and we can call these object as Model Objects.

Model object is simple java class consist of setters and getters methods so that we will use these object when want store data in database. Each row in table will mapping to Model object instance before perform any database action.

So simply we can say any action like add, delete, read and update  going to perform then it need Model object instance and the model object should be modify or create.

If we able identify these actions and track then we can hold the all the information with respect to each and every thing which is going in the application.

Liferay have used great concept called Model Listeners so that we can use these Listeners to identify the changes in the Model objects.

Liferay Model Listeners:

Liferay Model listeners are event listeners which will be invoked or called when the changes occurred in the model objects.

For each model object we have model listener so it will listen the events or actions which is performed on model object. We can create model listener for any model class in the liferay.

If we want create new listener for existed model which are in portal level we will use the hook to do these job.We need to override some portal properties thorogh the hook

Example:

Syntax:

value.object.listeners.ActualModel Class Name=Our Custom Listener class

Example properties in hook portal.properties file


value.object.listener.com.liferay.portal.model.Address=
com.meera.audit.listeners.AddressListener
value.object.listener.com.liferay.portal.model.Contact=
com.meera.audit.listeners.ContactListener


Note:

The custom listener class should implement the ModelListener interface and it has some abstract methods we need to implement those. These methods will be called when the changes happened in the model object.

The following are methods in ModelListener interface and its methods


public interface ModelListener<T> {

       public void onAfterAddAssociation(
                     Object classPK, String associationClassName,
                     Object associationClassPK)
              throws ModelListenerException;

       public void onAfterCreate(T model) throws ModelListenerException;

       public void onAfterRemove(T model) throws ModelListenerException;

       public void onAfterRemoveAssociation(
                     Object classPK, String associationClassName,
                     Object associationClassPK)
              throws ModelListenerException;

       public void onAfterUpdate(T model) throws ModelListenerException;

       public void onBeforeAddAssociation(
                     Object classPK, String associationClassName,
                     Object associationClassPK)
              throws ModelListenerException;

       public void onBeforeCreate(T model) throws ModelListenerException;

       public void onBeforeRemove(T model) throws ModelListenerException;

       public void onBeforeRemoveAssociation(
                     Object classPK, String associationClassName,
                     Object associationClassPK)
              throws ModelListenerException;

       public void onBeforeUpdate(T model) throws ModelListenerException;

}


The concept is simple we will use respective model listeners and at the time of changes made in model objects then respective listener methods will be called. We will use some business logic in the Model Listener implementation methods to capture the action and store in our tables according to convenient.

Audit Message:

We will use some generic object to capture respective model and its actions data so that it will be common for all the models.

We will follow some message pattern so that all models will capture such information place in Audit Message object.

The following is audit message class properties.


public class AuditMessage{
       private JSONObject _additionalInfo;
       private String _className;
       private String _classPK;
       private String _clientHost;
       private String _clientIP;
       private long _companyId = -1;
       private String _eventType;
       private String _message;
       private String _serverName;
       private int _serverPort;
       private String _sessionID;
       private Date _timestamp;
       private long _userId = -1;
       private String _userName;

}


Message Bus:

Message bus is one of the concepts in liferay so that we can create some destinations and its respective listeners to send the information and perform further actions through its respective listeners.

Whenever any event is generated we will post information to configured destinations as soon as information posted in destination respective liters will be listening and will perform further activities.


Note:

Model Listeners is different from Message Bus Destination listeners both are not same.

Now abstract the concept:
  • Model leisters are the responsible to identify the changes in the model class.
  • As soon as changes listen by the model listeners and each model listener have some methods bases on change type or event type inside these methods based on model event type we will prepare generic Audit Message.
  • Once Audit Message is prepared we will post this message in particular destination using Liferay Message Bus or we can say routing message to respective destination.
  • As soon as Message posted in Destination respective event listener will be invoked now we will capture the information from Audit Message then we will save into our data base tables.
  • Finally model object events information is stored as Audit Event table and the table consist of the columns same as the properties in Audit Message.
  • So this concept we can apply for any model object so that we can capture the information.

Code Snippet to prepare Audit message and Post in destination

Take your ModelListenr say RoleModelListener and Action is ADD


public void onBeforeCreate(Role role)
throws ModelListenerException
{
try
{
//prepare Audit Message

AuditMessage auditMessage = AuditMessageBuilder.buildAuditMessage("ADD", com.liferay.portal.model.Role.class.getName(), role.getRoleId(), null);

//message post to destination

AuditRouterUtil.route(auditMessage);

}
catch(Exception e)
{
throw new ModelListenerException(e);
}
}


The above code when we add role then it will be invoked and it will prepare Audit Message routing to respective destination.

As soon as it reach destination respective listener will be invoked and the audit data will be stored in Audit Event table.

Note:

We have audit hook and audit portlet to complete audit functionality in portal.

Audit Hook:

Audit hook is responsible to create model listeners for existed Model classes in portal and inside Model Listener we will create audit message in post into destination or we can say route the message to particular destination.

liferay-hook.xml file


<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.1.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_1_0.dtd">
<hook>
<portal-properties>portal.properties</portal-properties>
<language-properties>content/Language_en.properties</language-properties>
</hook>


Hook portal.properties file


value.object.listener.com.liferay.portal.model.Address=
com.meera.audit.listeners.AddressListener
value.object.listener.com.liferay.portal.model.Contact=
com.meera.audit.listeners.ContactListener


Audit Portlet:

Audit Portlet is responsible to show the audit information to admin the control panel.

In the portlet we have one entity called in Audit Event and it’s consisting of required columns to store audit information.

Audit portlet also consist of message bus configuration in messaging-spring.xml and this file should be available in portlet /WEB-INF/src/META-INF path.

And we need to specify the messaging-spring.xml file information in service.properties and it’s should available in /WEB-INF/src

We have another spring configuration file called auit-spring.xml file it consist of configuration related audit spring beans. This file should be available in portlet /WEB-INF/src/META-INF path. We need create and add configuration

We need to specify the auit-spring.xml file information in service.properties and it’s should available in /WEB-INF/src

In the portlet we need to change the database column types through  portlet-model-hints.xml file. This file should be available in portlet /WEB-INF/src/META-INF path


Deployment and Working

Step: 1

Before deploy these portlet we need to enable AuditFilter and override portal properties through portal-ext.properties file and it should be available in Liferay Home path.


# Enable the audit filter
com.liferay.portal.servlet.filters.audit.AuditFilter=true


Step: 2

 .lpg files and placed in liferay deploy directory so that it will be deployed.

Step: 3

After successful deployments of both hook and portlet then go to control panel in portal section you can see the audit portlet.

Access the portlet

Login as Admin in the liferay portal

Go to control panel






See the audit portlet in the users section


Access audit portlet then you can see all audit information in grid.


You can also search the audit information based on different search terms.


Click on any Audit event in data grid then you can see full details of respective event.



Reference Links



Author

Recent Posts

Recent Posts Widget

Popular Posts