Show live or logged in users

This blog is for creating an interface which will show number of live users and some other details.

First of all create a portlet which will provide interface and then create a hook within the portlet.Below link willl help to create hook in portlet.

http://www.learnandpost.com/2012/05/create-hook-inside-portlet-liferay.html

view.jsp

Add below line of code in portlet view.jsp

<%@page import="com.liferay.portal.service.UserLocalServiceUtil"%>
<%@page import="com.liferay.portal.model.User"%>
<%@page import="java.util.Iterator"%>
<%@page import="com.services.loggedinuser.LoggedInUsers"%>
<%@page import="java.util.Set"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
 
<style>
table {
    font-family: arial, sans-serif;
    border-collapse: collapse;
    width: 100%;
}
 
td, th {
    border: 1px solid #dddddd;
    text-align: left;
    padding: 8px;
}
th {
background-color: #e1e1e1;
}
tr:nth-child(even) {
    background-color: #eee;
}
</style>
 
<div style="border:1px solid #ccc;padding:5pt;">
<b>Total number of Live Users : </b>
 
<%
Set<Long> users_set = LoggedInUsers.loggedInUsers();
%>
<b><%=users_set.size() %></b><br/>
<table>
<thead>
<tr><th>User Id</th><th>Screen Name</th><th>Full Name</th><th>IP Address</th><th>Login Date</th></tr>
</thead>
<tbody>
<%
Iterator<Long> it = users_set.iterator();
while(it.hasNext()){
long user_id = it.next();
User user = UserLocalServiceUtil.getUser(user_id);
String fullName = user.getFullName();
String ipAddress = user.getLastLoginIP();
String screenname = user.getScreenName();
String loginDate = user.getLoginDate().toString();
%>
<tr>
<td><%=user_id %></td>
<td><%=screenname %></td>
<td><%= fullName%></td>
<td><%=ipAddress %></td>
<td><%=loginDate %></td>
</tr>
<%
}
%>
</tbody>
</table>
</div>
 
Now it s time to work on hook which we have create and which will tell about live users.
l iferay-hook.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">
 
<hook>
<portal-properties>portal.properties</portal-properties>
</hook>
portal.properties
login.events.post=com.services.loggedinuser.LoginPostAction 
servlet.session.destroy.events=com.services.loggedinuser.SessionDestroyAction
 
Create LoginPostAction and SessionDestroyAction class.
LoginPostAction
package com.services.loggedinuser;
import com.liferay.portal.kernel.events.Action;
import com.liferay.portal.util.PortalUtil;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class LoginPostAction extends Action {
@Override
public void run(HttpServletRequest request, HttpServletResponse response) {
long userId = PortalUtil.getUserId(request);
LoggedInUsers.addUser(userId);
System.out.println("Logged in user :"+userId);
}
}
 
SessionDestroyAction
package com.services.loggedinuser;
import com.liferay.portal.kernel.events.SessionAction;
import com.liferay.portal.kernel.util.WebKeys;
 
import javax.servlet.http.HttpSession;
 
public class SessionDestroyAction extends SessionAction{
@Override
public void run(HttpSession session) {
Long userId = (Long) session.getAttribute(WebKeys.USER_ID);
LoggedInUsers.removeUser(userId);
System.out.println("Log out user :"+userId);
}
}
Also create one model object for live users.
 
LoggedInUsers 
package com.services.loggedinuser;
 
import java.util.HashSet;
import java.util.Set;
 
public class LoggedInUsers {
private static Set<Long> users = new HashSet<Long>();
 
public static void addUser(long userId) {
users.add(userId);
}
 
public static void clearUsers() {
users.clear();
}
 
public static void removeUser(long userId) {
users.remove(userId);
}
 
public static int countUsers() {
return users.size();
}
 
public static boolean isLogged(long userId) {
return users.contains(userId);
}
 
public static Set<Long> loggedInUsers(){
return users;
}
}
 
Blogs
It is important to note that the list you get will likely never be 100% accurate. For example, if a user logs in and just closes the browser, they will show as logged in, even when they are not, until their session expires.

Also this code will never work in a cluster since it is based on per-node session creation/destruction. The only list you'll get is the list from the node you happen to connect to.
Thanks David for the detailed feedback. Could you mind to share your thought how i can resolve above issues.
I would be really thankful to you.

Regards
The browser close (or general disconnect from internet) issue you can use a short session with auto-extend enabled. That shortens the amount of time a user would show as logged in, even though they are not. Note that this cannot be eliminated because, if you just close the browser, there is absolutely nothing you can do about it.

For the cluster, you could message the events around the cluster to notify the other nodes. This has two issues, though. First it magnifies the session timeout issue above (you see invalid sessions from all nodes instead of just one), and second you may need to resolve cases where users are on multiple nodes (either because they are logged in using multiple devices or because you are not using sticky sessions).

These are not issues for Liferay, per se, these are issues that all internet systems struggle with. Closing the browser is simply not solvable using today's browser/http technology. The cluster issue can be resolved, but will take additional effort on your part to make it happen. But then you need to ask yourself if solving this problem actually gives you anything worthwhile or whether it is just throwing money away.