Lifeay Message Bus Portlet/ Handling bulk operations in Liferay
Objective:
Perform huge time taking operation in liferay
application.
Scenario:
In liferay application if we want send thousands of
mails or SMS then the response time is more. If mails are more then to complete
response user need to wait until request is completed. User cannot do any other
operations in application.
These scenarios are common in real time. Here
liferay provide Message Bus so that we can delegate task to other process and user continues with other operation in the application.exactly we can when response time is more in the application then we will delegate the operation to Message Bus.
Liferay message bus has lots of use, for now I just
explained how to send bulk mails using message bus.
Here once request is started we delegate request handling
to message bus so that message bus take caring bulk operation. Mean while request
will be relapsed quickly and process is run in back end.
Download LiferayBulkMailSender
from following location
You can find source and war file
Note:
Portlet developed in Liferay 6.1GA2 EE version
If you want deploy in CE version you just do changes in liferay-plugin-package.properties
Liferay 6.1 EE version
name=LiferayBulkMailSender
module-group-id=liferay-ee
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=EE
portal-dependency-jars=\
jstl-api.jar,\
jstl-impl.jar
portal-dependency-tlds=c.tld
liferay-versions=6.1.20
|
Liferay 6.1 CE version
name = LiferayBulkMailSender
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=LGPL
portal-dependency-jars=\
jstl-api.jar,\
jstl-impl.jar
portal-dependency-tlds=c.tld
liferay-versions=6.1.1
|
Procedure for deploy
portlet:
You can use war file and directly place in your portal deploy folder and
test or you can also use source to deploy portlet.
Once port let is deployed successfully you can see the portlet in sample
category
Please do portal mail configuration to send mails.
Whats
is message Bus?
The Message Bus can be used to exchange messages
between Liferay and other web applications, including deployed portlets and
plugins in general.
The developer can add Destinations to the Message
Bus, for each Destination you can register several MessageListeners. The client
sends a message to a Destination and the Message Bus will deliver this message
to every MessageListener that is listening to this Destination.
Note:
Message bus can use in many scenarios
Concept:
Message bus like tunnel between two or more
different nodes there we register all destinations each destination have multiple
listeners to receive messages.
We can say massage bus is responsible to transfer
messages from message senders to message listeners.
Building
block of system:
Message
Bus:
It is responsible to transfer messages from message
senders to message listenrsss.
Destinations:
Addresses or
end points to which listeners register to receive messages.
Listeners:
Consume messages received at destinations. They
receive all messages sent to their registered destinations
Senders:
Invoke the Message Bus to send messages to
destinations. We can say intiating the message bus
Note:
Message bus can send message between multiple plug-in
portlets or within same portlet.
Here I am explaining within one plug-in portlet.
Steps
to implement the concept
Step:1
Create messaging-spring.xml
in /src/META-INF/messaging-spring.xml
of your plug-in portlet.
Step:
2
Add following property in service.propertis file
spring.configs=WEB-INF/classes/META-INF/messaging-spring.xml
Note:
If your portlet already use service builder or
service layer then service.propertis already generated if not you can create in
/src/service.properties directory
and add property.
Step:
3
Configure Message Destination and Message Listers in
messaging-spring.xml by using bean called PluginMessagingConfigurator
this will take two properties one is messageListeners is map type and
other is destinations is list type.
Once we register listeners and destination we need
to configure respective beans which we referred as destinations and listeners
means implementation beans.
Step:
4
Implement the listeners
Whatever our implementation we have to write in
listener and listener should implement MessageListener and we need to implement
receive(-----)
method.
Things
we need to Do:
- Create message
- Add properties to message means data.
- Send message to destination (initiating Message Bus or start senders)
- Receive message in destination (Listener)
Scenario:
Assume now we want send some mail notification to
all portal users assume portal may have thousands of users. If we want send
mail to more users to complete request it may take several minutes. Until complete
the request user can’t do other operation.
Now we are going to handle this scenario using
massage bus with asynchronous serial destination.
Note:
we have two types of destination asynchronous and synchronous.
When we use synchronous until finish request we can’t
do any operation in application. If you use asynchronous we can do other
operation before finish request. Means the task delegate to massage bus and it
will be take caring mail sending process.
To configure asynchronous destination we will use SerialDestincation.java
class
As I said earlier steps now we will implement for
bulk mails sender
Create
messaging-spring.xml and
Configure listeners and destinations
Create messaging-spring.xml in src/META-INF
and configure destination and leisters
<?xml version="1.0"?>
<beans
default-destroy-method="destroy"
default-init-method="afterPropertiesSet"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Listeners -->
<bean id="liferay.bulk.mail_listener" class="com.meera.bulk.mail.BulkMaulSenderListenerImpl"
/>
<!-- Destinations
-->
<bean id="liferay.bulk.mail.sender.destination"
class="com.liferay.portal.kernel.messaging.SerialDestination">
<property name="name" value="liferay/bulk/mail/destination"
/>
</bean>
<!-- Configurator
-->
<bean id="messagingConfigurator" class="com.liferay.portal.kernel.messaging.config.PluginMessagingConfigurator">
<property name="messageListeners">
<map key-type="java.lang.String" value-type="java.util.List">
<entry key="liferay/bulk/mail/destination">
<list value- type="com.liferay.portal.kernel.messaging.MessageListener">
<ref bean="liferay.bulk.mail_listener" />
</list>
</entry>
</map>
</property>
<property name="destinations">
<list>
<ref bean="liferay.bulk.mail.sender.destination"/>
</list>
</property>
</bean>
</beans>
|
Configure
spring config property in service.properties file
Now add following property in service.properties in the
following location src/service.properties
spring.configs=WEB-INF/classes/META-INF/messaging-spring.xml
Now
create message and send message to destination
package
com.meera.bulk.mail;
import
java.io.IOException;
import
javax.portlet.ActionRequest;
import
javax.portlet.ActionResponse;
import
javax.portlet.PortletException;
import
com.liferay.portal.kernel.messaging.Message;
import
com.liferay.portal.kernel.messaging.MessageBusUtil;
import
com.liferay.portal.kernel.util.ParamUtil;
import
com.liferay.util.bridges.mvc.MVCPortlet;
public class
BulkMailSenderAction extends
MVCPortlet {
public void
sendMessage(
ActionRequest
actionRequest, ActionResponse actionResponse)
throws
IOException, PortletException {
System.out.println("====sendMessage===");
String
mailSubject=ParamUtil.getString(actionRequest,"mailSubject");
String
mailBody=ParamUtil.getString(actionRequest,"mailBody");
String
senderMailAddress=mailBody=ParamUtil.getString(actionRequest,"senderEmailAddess");
Message message = new
Message();
message.put("mailSubject",mailSubject);
message.put("mailBody",mailBody);
message.put("senderMailAddress",senderMailAddress);
try {
MessageBusUtil.sendMessage("liferay/bulk/mail/destination",
message);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
|
Receive
the message in Listener and process farther steps
package
com.meera.bulk.mail;
import
java.util.List;
import
javax.mail.internet.InternetAddress;
import
com.liferay.mail.service.MailServiceUtil;
import
com.liferay.portal.kernel.log.Log;
import
com.liferay.portal.kernel.log.LogFactoryUtil;
import
com.liferay.portal.kernel.mail.MailMessage;
import
com.liferay.portal.kernel.messaging.Message;
import
com.liferay.portal.kernel.messaging.MessageListener;
import
com.liferay.portal.model.User;
import
com.liferay.portal.service.UserLocalServiceUtil;
public class
BulkMaulSenderListenerImpl implements
MessageListener {
public void
receive(Message message) {
try {
doReceive(message);
}
catch
(Exception e) {
_log.error("Unable
to process message " + message, e);
}
}
protected void
doReceive(Message message)
throws
Exception {
String mailSubject = (String)message.get("mailSubject");
String mailBody = (String)message.get("mailBody");
String senderEmailAddess =(String)message.get("senderEmailAddess");
List<User>
usersList=UserLocalServiceUtil.getUsers(1,UserLocalServiceUtil.getUsersCount());
MailMessage mailMessage=new
MailMessage();
mailMessage.setBody(mailBody);
mailMessage.setSubject(mailSubject);
mailMessage.setFrom(new
InternetAddress(senderEmailAddess));
for(User
user:usersList){
mailMessage.setTo(new
InternetAddress(user.getEmailAddress()));
MailServiceUtil.sendEmail(mailMessage);
System.out.println("mail
sent to..::============:"+user.getEmailAddress());
}
}
private static
Log _log =
LogFactoryUtil.getLog(BulkMaulSenderListenerImpl.class);
}
|
Now we cans send mails and we need not to wait for
finish the task. Task is running back end so that user can do other operations.
Note:
In this example to show quick view i just commented
the mail sending code because until configure mail configuration in portal we can’t
send mails, for this reason I just commented the mail code and i written dummy
for loop with one lack count iteration.
When you submit button request will be finished quickly
but you can see server console back end loop is iterating for one lack times.
This is just for quick understanding of this portlet
after you configure portal mail configuration then you can uncomment the mail
code and test
Observations:
After deploy the portlet just drag and drop portlet
and click on Send Bulk Mail button as soon as you click the button your request
will be finished soon but in back end process is still continuing to send mails.
To understand this please sees the server console so that you can understand
all.
Important
points:
- Liferay provide message bus so that we can send message from message senders to message listeners.
- This message bus can send or receive messages from different plug-in contexts or within same portlet.
- Message Bus having multiple destinations and each destination has multiple listeners to receive messages.
- Message sender is initiating message bus to send message to end points or destinations. As soon as message reaches the destination respective leisters will receive the messages and it will start further process.
- We have two types of destination synchronous and asynchronous. Asynchronous destinations release the request even request is not complete but synchronous destinations are release the request once process or task finished.
Screens:
Mail
form
Message
after submit form
Server
console after request is completed
Reference:
Author
Meera
Prince