- Configure CometD servlet in portlet web.xml
- Implement Data Producer to produce data
- Implement Service to publish data on Channels Using Bayeux
- Use CometD java script in client side to subscribe channel and show data.
|
<servlet>
<servlet-name> cometd</servlet-name>
<servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
<init-param>
<param-name>transports</param-name>
<param-value>org.cometd.websocket.server.WebSocketTransport</param-value>
</init-param>
<init-param>
<param-name>services</param-name>
<param-value>com.meera.commetd.StockPriceService</param-value>
</init-param>
<init-param>
<param-name>maxLazyTimeout</param-name>
<param-value>2000</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> cometd</servlet-name>
<url-pattern>/ cometd/*</url-pattern>
</servlet-mapping>
|
|
bayeuxServer.createChannelIfAbsent(channelName, newConfigurableServerChannel.Initializer()
{
public void configureChannel(ConfigurableServerChannel channel)
{
channel.setPersistent( true);
channel.setLazy( true);
}
});
|
|
ServerChannel channel = bayeuxServer.getChannel(channelName);
channel.publish(sender, data);
|
|
var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
cometd.configure({
url: cometURL,
logLevel: 'debug'
});
cometd.addListener('/meta/handshake', _metaHandshake);
cometd.addListener('/meta/connect', _metaConnect);
cometd.handshake();
|
|
cometd.subscribe('/stock/*', function(message)
{
var data = message.data;
});
|
|
<scriptsrc= "http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/cometd-namespace.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/cometd-json.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/AckExtension.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/TransportRegistry.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/Transport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/RequestTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/WebSocketTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath()%> /js/comet/CallbackPollingTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/LongPollingTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/Utils.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/Cometd.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/jquery.cometd.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/application.js"></script>
|
|
<web-app id= "WebApp_ID" version= "2.4"xmlns= "http://java.sun.com/xml/ns/j2ee"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>LiferayCommetDRevserseAjax- portlet</display-name>
<servlet>
<servlet-name> cometd</servlet-name>
<servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
<init-param>
<param-name>transports</param-name>
<param-value>org.cometd.websocket.server.WebSocketTransport</param-value>
</init-param>
<init-param>
<param-name>services</param-name>
<param-value>com.meera.commetd.StockPriceService</param-value>
</init-param>
<init-param>
<param-name>maxLazyTimeout</param-name>
<param-value>2000</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> cometd</servlet-name>
<url-pattern>/ cometd/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/ cometd/*</url-pattern>
</filter-mapping>
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>
<taglib-location>
/WEB-INF/ tld/ liferay-portlet.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://liferay.com/tld/aui</taglib-uri>
<taglib-location>/WEB-INF/ tld/aui.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
|
|
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.inject.Inject;
import org.cometd.annotation.Service;
import org.cometd.annotation.Session;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ConfigurableServerChannel;
import org.cometd.bayeux.server.LocalSession;
import org.cometd.bayeux.server.ServerChannel;
@Service
public class StockPriceService implements StockPriceEmitter.Listener
{
@Inject
private BayeuxServer bayeuxServer;
@Session
private LocalSession sender;
public void onUpdates(List<StockPriceEmitter.Update> updates)
{
for (StockPriceEmitter.Update update : updates)
{
// Create the channel name using the stock symbol
String channelName = "/stock/" + update.getSymbol().toLowerCase(Locale. ENGLISH);
// Initialize the channel, making it persistent and lazy
bayeuxServer.createChannelIfAbsent(channelName, newConfigurableServerChannel.Initializer()
{
public void configureChannel(ConfigurableServerChannel channel)
{
channel.setPersistent( true);
channel.setLazy( true);
}
});
// Convert the Update business object to a CometD-friendly format
Map<String, Object> data = new HashMap<String, Object>(4);
data.put("symbol", update.getSymbol());
data.put("oldValue", update.getOldValue());
data.put("newValue", update.getNewValue());
System. out.println("===========================");
// Publish to all subscribers
ServerChannel channel =bayeuxServer.getChannel(channelName);
channel.publish(sender, data);
}
}
}
|
|
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class StockPriceEmitter implements Runnable {
private final ScheduledExecutorService scheduler = Executors
. newSingleThreadScheduledExecutor();
private final List<String> symbols = new ArrayList<String>();
private final Map<String, Float> values = new HashMap<String, Float>();
private final List<Listener> listeners = newCopyOnWriteArrayList<Listener>();
public StockPriceEmitter() {
symbols.addAll(Arrays. asList("ORCL", "MSFT", "GOOG","YHOO", "FB"));
values.put("ORCL", 29.94f);
values.put("MSFT", 27.10f);
values.put("GOOG", 655.37f);
values.put("YHOO", 17.82f);
values.put("FB", 21.33f);
}
public List<Listener> getListeners() {
return listeners;
}
public void start() {
run();
}
public void stop() {
scheduler.shutdownNow();
}
public void run() {
Random random = new Random();
List<Update> updates = new ArrayList<Update>();
// Randomly choose how many stocks to update
int howMany = random.nextInt(symbols.size()) + 1;
for ( int i = 0; i < howMany; ++i) {
// Randomly choose which one to update
int which = random.nextInt(symbols.size());
String symbol = symbols.get(which);
float oldValue = values.get(symbol);
// Randomly choose how much to update
boolean sign = random.nextBoolean();
float howMuch = random.nextFloat();
float newValue = oldValue + (sign ? howMuch : -howMuch);
// Store the new value
values.put(symbol, newValue);
updates.add( new Update(symbol, oldValue, newValue));
}
// Notify the listeners
for (Listener listener : listeners) {
listener.onUpdates(updates);
}
// Randomly choose how long for the next update
// We use a max delay of 1 second to simulate a high rate of updates
long howLong = random.nextInt(1000);
scheduler.schedule( this, howLong, TimeUnit. MILLISECONDS);
}
public static class Update {
private final String symbol;
private final float oldValue;
private final float newValue;
public Update(String symbol, float oldValue, floatnewValue) {
this.symbol = symbol;
this.oldValue = oldValue;
this.newValue = newValue;
}
public String getSymbol() {
return symbol;
}
public float getOldValue() {
return oldValue;
}
public float getNewValue() {
return newValue;
}
}
public interface Listener extends EventListener {
void onUpdates(List<Update> updates);
}
}
|
|
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class LiferayCommetDReverseAjax extends MVCPortlet {
private StockPriceEmitter emitter;
public void startStockUpdates(
ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException {
emitter = new StockPriceEmitter();
StockPriceService service(StockPriceService)getPortletContext().
getAttribute(StockPriceService. class.getName());
// Register the service as a listener of the emitter
emitter.getListeners().add(service);
// Start the emitter
emitter.start();
}
public void stopStockUpdates(
ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException {
// emitter = new StockPriceEmitter();
emitter.stop();
}
}
|
|
( function($)
{
var cometd = $.cometd;
//alert( cometd);
$(document).ready( function()
{
function _connectionEstablished()
{
$('#body').append('<div>CometD Connection Established</div>');
}
function _connectionBroken()
{
$('#body').append('<div>CometD Connection Broken</div>');
}
function _connectionClosed()
{
$('#body').append('<div>CometD Connection Closed</div>');
}
// Function that manages the connection status with the Bayeuxserver
var _connected = false;
function _metaConnect(message)
{
if (cometd.isDisconnected())
{
_connected = false;
_connectionClosed();
return;
}
var wasConnected = _connected;
_connected = message.successful === true;
if (!wasConnected && _connected)
{
_connectionEstablished();
}
else if (wasConnected && !_connected)
{
_connectionBroken();
}
}
// Function invoked when first contacting the server and
// when the server has lost the state of this client
function _metaHandshake(handshake)
{
if (handshake.successful === true)
{
cometd.batch( function()
{
cometd.subscribe('/stock/*', function(message)
{
var data = message.data;
var symbol = data.symbol;
var value = data.newValue;
// alert(symbol);
var id = 'stock_'+ symbol;
var symbolDiv=document.getElementById(id);
if (!symbolDiv)
{
symbolDiv = document.createElement('div');
symbolDiv.id =id;
document.getElementById('stocks').appendChild(symbolDiv);
}
symbolDiv.innerHTML = '<span class="symbol">' + symbol + ': <b>' + value + '</b></span>';
});
// Publish on a service channel since the message is for the server only
//cometd.publish('/stock/*', { name: 'World' });
});
}
}
// Disconnect when the page unloads
$(window).unload( function()
{
cometd.disconnect( true);
});
var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
cometd.configure({
url: cometURL,
logLevel: 'debug'
});
cometd.addListener('/meta/handshake', _metaHandshake);
cometd.addListener('/meta/connect', _metaConnect);
cometd.handshake();
});
})(jQuery);
|
|
<%@ include file= "init.jsp"%>
<scriptsrc= "http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/cometd-namespace.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/cometd-json.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/AckExtension.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/TransportRegistry.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/Transport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/RequestTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/WebSocketTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath()%> /js/comet/CallbackPollingTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/LongPollingTransport.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/Utils.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/Cometd.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/jquery.cometd.js"></script>
<script type= "text/javascript" src= "<%=renderRequest.getContextPath() %> /js/comet/application.js"></script>
<%--
The reason to use a JSP is that it is very easy to obtain server-side configuration
information (such as the contextPath) and pass it to the JavaScript environment on the client.
--%>
<style>
#stocks .symbol b{
color: red;
}
#controler-table td{
padding-left: 30px;
}
</style>
<script type= "text/javascript">
var config = {
contextPath: '<%=renderRequest.getContextPath()%>'
};
</script>
<portlet:actionURL var= "startStockUpdates" name= "startStockUpdates">
</portlet:actionURL>
<portlet:actionURL var= "stopStockUpdates" name= "stopStockUpdates">
</portlet:actionURL>
<h2> Liferay CometD Ajax Push Portlet</h2>
<br/>
<table id= "controler-table">
<tr>
<td><a href= "<%=startStockUpdates.toString()%> ">Start</a></td>
<td><a href= "<%=stopStockUpdates.toString()%> ">Stop</a></td>
</tr>
</table>
<br/>
<div id= "stocks"></div>
|


