Index: components/statistics/src/java/org/apache/jetspeed/statistics/impl/UserStatsImpl.java
===================================================================
--- components/statistics/src/java/org/apache/jetspeed/statistics/impl/UserStatsImpl.java	(revision 530210)
+++ components/statistics/src/java/org/apache/jetspeed/statistics/impl/UserStatsImpl.java	(working copy)
@@ -16,7 +16,12 @@
  */
 package org.apache.jetspeed.statistics.impl;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 import org.apache.jetspeed.statistics.UserStats;
+
+import com.sun.org.apache.bcel.internal.util.ByteSequence;
 
 /**
  * UserStatsImpl
@@ -30,7 +35,9 @@
 
     private String username;
 
-    private int numberOfSessions;
+    private int numberOfSessions;
+    
+    private InetAddress inetAddress;
 
     /*
      * (non-Javadoc)
@@ -73,5 +80,45 @@
     {
         this.username = username;
 
-    }
+    }
+
+	/* (non-Javadoc)
+	 * @see org.apache.jetspeed.statistics.UserStats#getInetAddress()
+	 */
+	public InetAddress getInetAddress() {
+		return inetAddress;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.jetspeed.statistics.UserStats#setInetAddress(java.net.InetAddress)
+	 */
+	public void setInetAddress(InetAddress inetAddress) {
+		this.inetAddress = inetAddress;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.jetspeed.statistics.UserStats#setInetAddressFromIp(java.lang.String)
+	 */
+	public void setInetAddressFromIp(String ip) throws UnknownHostException {
+		this.inetAddress = InetAddress.getByName(ip);		
+	}
+
+	/**
+	 * Checks whether these two object match. Simple check for
+	 * just the ipaddresse and username.
+	 * 
+	 * @param Object instanceof UserStats
+	 */
+	public boolean equals(Object obj) {
+		
+		boolean equals = true;
+		if(!(obj instanceof UserStats))
+			return false;
+		
+		UserStats userstat = (UserStats)obj;
+		if(this.inetAddress.equals(userstat.getInetAddress()) && this.username.equals(userstat.getUsername()))
+			equals = true;
+		
+		return equals;
+	}
 }
Index: components/statistics/src/java/org/apache/jetspeed/statistics/impl/PortalStatisticsImpl.java
===================================================================
--- components/statistics/src/java/org/apache/jetspeed/statistics/impl/PortalStatisticsImpl.java	(revision 530210)
+++ components/statistics/src/java/org/apache/jetspeed/statistics/impl/PortalStatisticsImpl.java	(working copy)
@@ -340,25 +340,27 @@
             {
                 synchronized (currentUsers)
                 {
-                    UserStats userStats = (UserStats) currentUsers
-                            .get(userName);
-                    if (userStats == null)
+                	UserStats userStats = null;
+                	
+                	Map users = (Map)currentUsers.get(userName);                	
+                	if(users != null && users.size() > 0)
+                	{
+                		userStats = (UserStats) users.get(ipAddress);                		
+                	}                	
+            	
+                	if(userStats != null)
                     {
-                        userStats = new UserStatsImpl();
-                        userStats.setNumberOfSession(0);
-                        userStats.setUsername(userName);
-                        currentUsers.put(userName, userStats);
-                    }else
-                    {
                     	// only decrement if user has been logged in
                     	currentUserCount = currentUserCount - 1;
+                        
+                    	userStats.setNumberOfSession(userStats
+                                .getNumberOfSessions() - 1);                    
+                        if (userStats.getNumberOfSessions() <= 0)
+                        {
+                        	users.remove(ipAddress);
+                            currentUsers.put(userName, users);
+                        }
                     }
-                    userStats.setNumberOfSession(userStats
-                            .getNumberOfSessions() - 1);
-                    if (userStats.getNumberOfSessions() <= 0)
-                    {
-                        currentUsers.remove(userName);
-                    }
                 }
             }
 
@@ -400,6 +402,7 @@
             Principal principal = req.getUserPrincipal();
             String userName = (principal != null) ? principal.getName()
                     : "guest";
+            String ipAddress = req.getRemoteAddr();
             Timestamp timestamp = new Timestamp(System.currentTimeMillis());
             UserLogRecord record = new UserLogRecord();
 
@@ -409,22 +412,36 @@
 
                 synchronized (currentUsers)
                 {
-                    UserStats userStats = (UserStats) currentUsers
-                            .get(userName);
-                    if (userStats == null)
+                	
+                	UserStats userStats = null;
+                	
+                	Map users = (Map)currentUsers.get(userName);                	
+                	if(users != null && users.size() > 0)
+                	{
+                		userStats = (UserStats) users.get(ipAddress);                		
+                	}
+                	else
+                	{
+                		users = new TreeMap();
+                	}
+                	
+                	if(userStats == null)
                     {
                         userStats = new UserStatsImpl();
                         userStats.setNumberOfSession(0);
                         userStats.setUsername(userName);
-                        currentUsers.put(userName, userStats);
+                        userStats.setInetAddressFromIp(ipAddress);                        
                     }
+                    
                     userStats.setNumberOfSession(userStats
                             .getNumberOfSessions() + 1);
+                    users.put(ipAddress, userStats);
+            		currentUsers.put(userName, users);
                 }
             }
 
             record.setUserName(userName);
-            record.setIpAddress(req.getRemoteAddr());
+            record.setIpAddress(ipAddress);
             record.setStatus(STATUS_LOGGED_IN);
             record.setTimeStamp(timestamp);
             record.setMsElapsedTime(msElapsedLoginTime);
Index: components/portal/src/java/org/apache/jetspeed/container/session/PortalSessionsManagerImpl.java
===================================================================
--- components/portal/src/java/org/apache/jetspeed/container/session/PortalSessionsManagerImpl.java	(revision 530210)
+++ components/portal/src/java/org/apache/jetspeed/container/session/PortalSessionsManagerImpl.java	(working copy)
@@ -236,4 +236,12 @@
             pasm.invalidateSession();
         }
     }
+
+	/* (non-Javadoc)
+	 * @see org.apache.jetspeed.container.session.PortalSessionsManager#sessionCount()
+	 */
+	public int sessionCount() {
+		
+		return portalSessionsRegistry.size();
+	}
 }
Index: components/portal/src/java/org/apache/jetspeed/layout/ajax-xml/userlist.vm
===================================================================
--- components/portal/src/java/org/apache/jetspeed/layout/ajax-xml/userlist.vm	(revision 0)
+++ components/portal/src/java/org/apache/jetspeed/layout/ajax-xml/userlist.vm	(revision 0)
@@ -0,0 +1,50 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*#
+<js>
+    <status>$status</status>
+    <action>$action</action>
+    #if($users.size() > 0 || $guestusers)
+    <users>
+    	#foreach( $user in $users )
+    	<user>
+    		#if($user.username)
+    			<username>$user.username</username>
+    		#end
+    		#if($user.sessions)
+    			<sessions>$user.sessions</sessions>
+    		#end
+    		#if($user.status)
+    			<status>$user.status</status>
+			#end
+			#if($user.ipaddress)
+    			<ipaddress>$user.ipaddress</ipaddress>
+    		#end
+    		#if($user.userinfo.size() > 0)
+    			<userinfo>
+				#foreach($key in $user.userinfo.keySet())
+    				<$key>$user.userinfo.get($key)</$key>
+				#end
+				</userinfo>
+    		#end
+	    </user>
+		#end
+    	#if($guestusers)
+    		<guests>$guestusers</guests>
+		#end
+    </users>
+    #end
+</js>
\ No newline at end of file
Index: components/portal/src/java/org/apache/jetspeed/layout/ajax-xml/userinfo.vm
===================================================================
--- components/portal/src/java/org/apache/jetspeed/layout/ajax-xml/userinfo.vm	(revision 0)
+++ components/portal/src/java/org/apache/jetspeed/layout/ajax-xml/userinfo.vm	(revision 0)
@@ -0,0 +1,29 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*#
+<js>
+    <status>$status</status>
+    <action>$action</action>
+    <username>$username</username> 
+    <type>$type</type>
+    #if($userinfo.size() > 0)
+	    <userinfo>
+		#foreach( $key in $userinfo.keySet() )
+    		<$key>$userinfo.get($key)</$key>
+		#end
+		</userinfo>
+	#end
+</js>
\ No newline at end of file
Index: components/portal/src/java/org/apache/jetspeed/layout/impl/Constants.java
===================================================================
--- components/portal/src/java/org/apache/jetspeed/layout/impl/Constants.java	(revision 530210)
+++ components/portal/src/java/org/apache/jetspeed/layout/impl/Constants.java	(working copy)
@@ -64,8 +64,17 @@
     public static final String FOLDER = "folder";
     public static final String FOLDERS = "folders";
     public static final String SIZES = "sizes";
-    public static final String RESOURCE_NAME = "name";
-
+    public static final String RESOURCE_NAME = "name";    
+    public static final String USERS = "users";
+    public static final String GUESTUSERS = "guestusers";
+    public static final String USERNAME = "username";
+    public static final String USERINFO = "userinfo";
+    public static final String SESSIONS = "sessions";
+    public static final String IPADDRESS = "ipaddress";
+    
+    public static final String OFFLINE = "offline";
+    public static final String ONLINE = "online";
+    
     public static final String STANDARD_MENUS = "standardMenus";
     public static final String CUSTOM_MENUS = "customMenus";
     public static final String MENU = "menu";
Index: components/portal/src/java/org/apache/jetspeed/layout/impl/BaseUserAction.java
===================================================================
--- components/portal/src/java/org/apache/jetspeed/layout/impl/BaseUserAction.java	(revision 0)
+++ components/portal/src/java/org/apache/jetspeed/layout/impl/BaseUserAction.java	(revision 0)
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jetspeed.layout.impl;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jetspeed.ajax.AJAXException;
+import org.apache.jetspeed.ajax.AjaxAction;
+import org.apache.jetspeed.ajax.AjaxBuilder;
+import org.apache.jetspeed.layout.PortletActionSecurityBehavior;
+import org.apache.jetspeed.om.page.Fragment;
+import org.apache.jetspeed.om.page.Page;
+import org.apache.jetspeed.page.PageManager;
+import org.apache.jetspeed.request.RequestContext;
+import org.apache.jetspeed.security.UserManager;
+
+/**
+ * Abstract portlet placement action
+ *
+ * @author <a>David Gurney</a>
+ * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
+ * @author <a href="mailto:mikko.wuokko@evtek.fi">Mikko Wuokko</a>
+ * @version $Id: $
+ */
+public abstract class BaseUserAction 
+    implements AjaxAction, AjaxBuilder, Constants 
+{
+    protected Log log = LogFactory.getLog(BaseUserAction.class);    
+	protected String template = null;
+    protected UserManager userManager = null;
+    protected String errorTemplate = null;
+    protected RolesSecurityBehavior securityBehavior;
+    
+    public BaseUserAction(String template, 
+                             String errorTemplate, 
+                             RolesSecurityBehavior securityBehavior)
+    {
+        this.template = template;
+        this.errorTemplate = errorTemplate;
+        this.securityBehavior = securityBehavior;
+    }
+
+    public BaseUserAction(String template, 
+            String errorTemplate, 
+            UserManager userManager)
+    {
+        this.template = template;
+        this.errorTemplate = errorTemplate;
+        this.userManager = userManager;
+        this.securityBehavior = null;
+    }
+    
+    public BaseUserAction(String template, 
+                             String errorTemplate, 
+                             UserManager userManager,
+                             RolesSecurityBehavior securityBehavior)
+    {
+        this(template, errorTemplate, securityBehavior);
+        this.userManager = userManager;
+    }
+
+    public boolean buildContext(RequestContext requestContext, Map responseContext)
+    {
+        return true;
+    }
+
+    public boolean buildErrorContext(RequestContext requestContext,
+            Map responseContext) 
+    {
+        responseContext.put(STATUS, "failure");
+
+        // Check for the case where we don't know basic information
+        if (responseContext.get(ACTION) == null)
+        {
+            responseContext.put(ACTION, "unknown");
+        }
+
+        if (responseContext.get(PORTLETID) == null)
+        {
+            responseContext.put(PORTLETID, "unknown");
+        }
+
+        return true;
+    }
+
+    public String getErrorTemplate()
+    {
+        return errorTemplate;
+    }
+
+    public String getTemplate()
+    {
+        return template;
+    }
+
+    public boolean checkAccess(RequestContext context, String action)
+    {
+        boolean access = true;
+        if (null != securityBehavior)
+        {
+            access = securityBehavior.checkAccess(context, action);
+        }
+        return access;
+    }
+
+    public boolean createNewPageOnEdit(RequestContext context)
+    {
+        return securityBehavior.createNewPageOnEdit(context);        
+    }
+        
+    // TODO: support nested fragments
+    public Fragment getFragmentIdFromLocation(int row, int column, Page page)
+    {
+        Fragment root = page.getRootFragment();
+        Iterator fragments = root.getFragments().iterator();
+        while (fragments.hasNext())
+        {
+            Fragment fragment = (Fragment)fragments.next();
+            if (fragment.getLayoutColumn() == column &&
+                fragment.getLayoutRow() == row)
+            {
+                return fragment;
+            }
+        }
+        return null;
+    }
+    
+    public boolean runBatch(RequestContext requestContext, Map resultMap) throws AJAXException
+    {
+        return run(requestContext, resultMap);
+    }
+    
+    public String getActionParameter(RequestContext requestContext, String name)
+    {
+        String parameter = requestContext.getRequestParameter(name);
+        if (parameter == null)
+        {
+            Object o = requestContext.getAttribute(name);
+            if (o != null)
+            {
+                if (o instanceof String)
+                    return (String)o;
+            }
+        }
+        return parameter;
+    }
+    
+    public Fragment getParentFragmentById(String id, Fragment root)
+    {
+        if ( id == null )
+        {
+            return null;
+        }
+        return searchForParentFragmentById( id, root );
+    }
+    
+    protected Fragment searchForParentFragmentById( String id, Fragment parent )
+    {   
+        // find fragment by id, tracking fragment parent
+        Fragment matchedParent = null;
+        if( parent != null ) 
+        {
+            // process the children
+            List children = parent.getFragments();
+            for( int i = 0, cSize = children.size() ; i < cSize ; i++) 
+            {
+                Fragment childFrag = (Fragment)children.get( i );
+                if ( childFrag != null ) 
+                {
+                    if ( id.equals( childFrag.getId() ) )
+                    {
+                        matchedParent = parent;
+                        break;
+                    }
+                    else
+                    {
+                        matchedParent = searchForParentFragmentById( id, childFrag );
+                        if ( matchedParent != null )
+                        {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return matchedParent;
+    }
+    
+       
+    /**
+     * Helper method to determine if a parameter is true. Prevents
+     * accidental NullPointerExceptions when comparing or or using
+     * the parameter value.
+     * @param parameter The value to be determined as boolean true or false.
+     * @return boolean true or false according to the @param value.
+     */
+    public boolean isTrue(String parameter)
+    {
+    	boolean isTrue = false;
+    	if(parameter != null)
+    	{
+    		if(parameter.equalsIgnoreCase("true"))
+    		{
+    			isTrue = true;
+    		}   			
+    	}
+    	return isTrue;
+    }
+    
+}
Index: components/portal/src/java/org/apache/jetspeed/layout/impl/GetUserListAction.java
===================================================================
--- components/portal/src/java/org/apache/jetspeed/layout/impl/GetUserListAction.java	(revision 0)
+++ components/portal/src/java/org/apache/jetspeed/layout/impl/GetUserListAction.java	(revision 0)
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jetspeed.layout.impl;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jetspeed.JetspeedActions;
+import org.apache.jetspeed.ajax.AJAXException;
+import org.apache.jetspeed.ajax.AjaxAction;
+import org.apache.jetspeed.ajax.AjaxBuilder;
+import org.apache.jetspeed.container.session.PortalSessionsManager;
+import org.apache.jetspeed.request.RequestContext;
+import org.apache.jetspeed.security.SecurityException;
+import org.apache.jetspeed.security.SecurityHelper;
+import org.apache.jetspeed.security.User;
+import org.apache.jetspeed.security.UserManager;
+import org.apache.jetspeed.security.UserPrincipal;
+import org.apache.jetspeed.statistics.PortalStatistics;
+import org.apache.jetspeed.statistics.UserStats;
+
+/**
+ * Returns the list of currently logged in users
+ * and optionally also the offline users and
+ * number of guest user sessions
+ * 
+ * AJAX action:
+ * 		action: getuserlist
+ * 
+ * AJAX Parameters: 
+ * 		guest:	whether we should return also the guest sessions
+ * 			   	true | false (default)
+ *      userinfo: whether we should include also userinfo
+ *      		true | false (default)
+ *      offline: whether we should include offline users
+ *      		true | false (default)
+ *      all: 	return every bits and piece there is
+ *      		true | false (default)
+ * @author <a href="mailto:mikko.wuokko@evtek.fi">Mikko Wuokko</a>
+ * @version $Id: $
+ */
+public class GetUserListAction 
+    extends BaseUserAction 
+    implements AjaxAction, AjaxBuilder, Constants
+{
+    protected Log log = LogFactory.getLog(GetUserListAction.class);
+    private PortalStatistics pstats = null;
+    private PortalSessionsManager psm = null;
+
+    private final String PARAM_GUEST = "guest";
+    private final String PARAM_USERINFO = "userinfo";
+    private final String PARAM_OFFILE = "offline";
+    private final String PARAM_ALL = "all";
+    
+    public GetUserListAction(String template, 
+                            String errorTemplate, 
+                            UserManager um,
+                            PortalStatistics pstats,
+                            PortalSessionsManager psm)
+    {
+        this(template, errorTemplate, um, pstats, psm, null); 
+    }
+    
+    public GetUserListAction(String template, 
+            String errorTemplate, 
+            UserManager um,
+            PortalStatistics pstats,
+            PortalSessionsManager psm, 
+            RolesSecurityBehavior securityBehavior)
+    {
+    	super(template, errorTemplate, um, securityBehavior); 
+    	this.pstats = pstats;
+    	this.psm = psm;
+    }
+    
+    public boolean run(RequestContext requestContext, Map resultMap)
+            throws AJAXException
+    {
+        boolean success = true;
+        String status = "success";
+        
+    	// Do a security check if a behavior is set
+    	if(securityBehavior != null)
+    	{
+    		if(!checkAccess(requestContext, JetspeedActions.EDIT))
+    		{
+    			success = false;
+                resultMap.put(REASON, "Insufficient access see user details.");                
+                return success;
+    		}
+    	}
+
+    	boolean includeGuests;
+    	boolean includeUserInfo;
+        boolean includeOffline;
+        boolean includeAll = isTrue(getActionParameter(requestContext, PARAM_ALL));
+        
+        // Set everything true if "all" is set to true
+        if(includeAll){
+        	includeGuests = true;
+        	includeUserInfo = true;
+        	includeOffline = true;
+        }
+        else
+        {        
+        	includeOffline = isTrue(getActionParameter(requestContext, PARAM_OFFILE));
+        	includeGuests = isTrue(getActionParameter(requestContext, PARAM_GUEST));
+        	includeUserInfo = isTrue(getActionParameter(requestContext, PARAM_USERINFO));
+        }
+        
+        int numberOfCurrentUsers = 0;
+        int numberOfCurrentLoggedInUsers = 0;
+        
+        Collection users = new ArrayList();
+        Collection loggedInUsers = new ArrayList();
+        Collection offlineUsers = new ArrayList();
+
+        try
+        {
+            resultMap.put(ACTION, "getuserlist");
+            // Check that the statistics is not disabled 
+        	if(pstats != null)
+        	{
+        		// Get the user counts
+        		numberOfCurrentUsers = psm.sessionCount();
+        		numberOfCurrentLoggedInUsers = pstats.getNumberOfLoggedInUsers();
+
+        		/*
+        		 * An helper to track the users that have already been added to the resultMap 
+        		 * as logged in users, so there wouldn't be an offline duplicate. Trying
+        		 * to prevent some overhead with this.
+        		 * Needs some more thinking, maybe some helper functions to portal statistics
+        		 * to get just the names of the logged in users for contains comparison.
+        		 */ 
+        		List addedUserNames = new ArrayList();
+        		
+        		// If no logged in users, nothing to do
+        		if(numberOfCurrentLoggedInUsers > 0)
+        		{
+
+        			// Logged in users is a list of UserStats objects
+        			Iterator usersIter = pstats.getListOfLoggedInUsers().iterator();
+        			while(usersIter.hasNext())
+        			{
+        				Map userMap = (Map)usersIter.next();
+        				if(userMap != null && userMap.size() > 0)
+        				{
+        					Iterator userKeyIter = userMap.keySet().iterator();
+        					while(userKeyIter.hasNext())
+        					{
+        						String userStatKey = String.valueOf(userKeyIter.next());
+        						UserStats userStat = (UserStats)userMap.get(userStatKey);
+        						
+        						Map singleUserMap = new HashMap();
+        						singleUserMap.put(USERNAME, userStat.getUsername());
+        						singleUserMap.put(SESSIONS, Integer.valueOf(userStat.getNumberOfSessions()));
+        						singleUserMap.put(STATUS, ONLINE);
+        						singleUserMap.put(IPADDRESS, userStat.getInetAddress().getHostAddress());
+        						if(includeUserInfo)
+        						{
+        							singleUserMap.put(USERINFO, getUserInfo(userStat.getUsername()));
+        						}
+        						
+        						// Add user to the helper if not added yet
+        						if(!addedUserNames.contains(userStat.getUsername()))
+        							addedUserNames.add(userStat.getUsername());
+        						
+        						loggedInUsers.add(singleUserMap);
+        					}
+        					        					
+        				}
+        			}
+        			
+        			// Adding online users to the collection
+        			users.addAll(loggedInUsers);
+                }
+        		
+        		// Check whether we should iterate through all of the users or just logged in ones
+    			if(includeOffline)
+    			{
+    				Iterator allUusers = userManager.getUsers("");
+    				while(allUusers.hasNext())
+        			{
+        				User user = (User)allUusers.next();
+        				Principal userPrincipal = SecurityHelper.getPrincipal(user.getSubject(), UserPrincipal.class);
+        				if(userPrincipal != null)
+        				{
+        					// Check if this users is already added as online user
+        					if(!addedUserNames.contains(userPrincipal.getName()))
+        					{
+        						Map userMap = new HashMap();
+        						userMap.put(USERNAME, userPrincipal.getName());
+        						userMap.put(STATUS, OFFLINE);
+        						if(includeUserInfo)
+        						{
+        							userMap.put(USERINFO, getUserInfo(userPrincipal.getName()));        						}
+
+        						offlineUsers.add(userMap);
+        					}
+        				}
+        			}
+    				
+        			// Adding online users to the collection
+        			users.addAll(offlineUsers);
+    			}
+        		
+        		// Add the logged in users to resultMap
+                resultMap.put(USERS, users);
+                
+        		if(includeGuests)        			
+        		{
+        			// Add number of guest accounts to resultMap
+        			int guestUserCount = numberOfCurrentUsers - numberOfCurrentLoggedInUsers;
+                    resultMap.put(GUESTUSERS, Integer.valueOf(guestUserCount));
+        		}
+                	
+        	}
+        	else
+        	{
+        		status = "failure";
+        		resultMap.put(REASON, "Statistics not available");
+        		return false;
+        	}
+            resultMap.put(STATUS, status);
+        } 
+        catch (Exception e)
+        {
+            log.error("exception statistics access", e);
+            resultMap.put(REASON, e.toString());
+            success = false;
+        }
+        return success;
+    }    
+
+    
+    /**
+     * Helper method to get the user information of an user as Map.
+     * 
+     * @param username Name of the user of request
+     * @return Map containing the user information keyed by the name of the attribute.
+     * @throws SecurityException
+     * @throws BackingStoreException
+     */
+    private Map getUserInfo(String username) throws SecurityException, BackingStoreException
+    {
+    	Map userInfo = new HashMap();
+    	User user =  userManager.getUser(username);
+		if(user != null)
+		{
+        	Preferences userPrefs = user.getUserAttributes();
+        	String[] userPrefKeys = userPrefs.keys();
+        
+        	for(int i = 0; i<userPrefKeys.length; i++)
+        	{
+        		userInfo.put(userPrefKeys[i], userPrefs.get(userPrefKeys[i], "No value"));                		
+        	}
+		}
+		
+		return userInfo;
+    }
+    
+}
Index: components/portal/src/java/org/apache/jetspeed/layout/impl/GetUserInformationAction.java
===================================================================
--- components/portal/src/java/org/apache/jetspeed/layout/impl/GetUserInformationAction.java	(revision 0)
+++ components/portal/src/java/org/apache/jetspeed/layout/impl/GetUserInformationAction.java	(revision 0)
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jetspeed.layout.impl;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.prefs.Preferences;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jetspeed.ajax.AJAXException;
+import org.apache.jetspeed.ajax.AjaxAction;
+import org.apache.jetspeed.ajax.AjaxBuilder;
+import org.apache.jetspeed.request.RequestContext;
+import org.apache.jetspeed.security.User;
+import org.apache.jetspeed.security.UserManager;
+
+/**
+ * Retrieve user information of the current user
+ * 
+ * AJAX action:
+ * 		action = getuserinfo
+ * 
+ * AJAX Parameters:
+ * 		none
+ *     
+ * @author <a href="mailto:mikko.wuokko@evtek.fi">Mikko Wuokko</a>
+ * @version $Id: $
+ */
+public class GetUserInformationAction 
+    extends BaseUserAction 
+    implements AjaxAction, AjaxBuilder, Constants
+{
+    protected Log log = LogFactory.getLog(GetUserInformationAction.class);
+
+    public GetUserInformationAction(String template, 
+                            String errorTemplate, 
+                            UserManager um)
+    {
+        super(template, errorTemplate, um); 
+    }
+    
+    public boolean run(RequestContext requestContext, Map resultMap)
+            throws AJAXException
+    {
+        boolean success = true;
+        String status = "success";
+        try
+        {
+            resultMap.put(ACTION, "userinformation");
+            // Get the necessary parameters off of the request
+        	if(!requestContext.getUserPrincipal().getName().equals(userManager.getAnonymousUser()))
+        	{        		
+        		Principal principal = requestContext.getUserPrincipal();        		
+                resultMap.put(USERNAME, principal.getName());
+                resultMap.put(TYPE, principal.getClass().getName());
+                
+                // Loading the userinfo
+                User user = userManager.getUser(principal.getName());
+                if(user != null)
+                {
+                	Preferences prefs = user.getUserAttributes();
+                	String[] prefKeys = prefs.keys();
+                	Map prefsSet = new HashMap();
+                	for(int i = 0; i<prefKeys.length; i++)
+                	{
+                		prefsSet.put(prefKeys[i], prefs.get(prefKeys[i], "No value"));                		
+                	}
+                	resultMap.put(USERINFO, prefsSet);
+
+                }
+                	
+        	}
+        	else
+        	{
+        		status = "failure";
+        		resultMap.put(REASON, "Not logged in");
+        		return false;
+        	}
+            resultMap.put(STATUS, status);
+        } 
+        catch (Exception e)
+        {
+            log.error("exception with user account access", e);
+            resultMap.put(REASON, e.toString());
+            success = false;
+        }
+        return success;
+    }    
+
+}
Index: src/webapp/WEB-INF/assembly/jetspeed-services.xml
===================================================================
--- src/webapp/WEB-INF/assembly/jetspeed-services.xml	(revision 530210)
+++ src/webapp/WEB-INF/assembly/jetspeed-services.xml	(working copy)
@@ -100,7 +100,7 @@
             <ref bean="org.apache.jetspeed.prefs.PreferencesProvider"/>
           </entry>
           <entry key="org.apache.jetspeed.container.session.PortalSessionsManager">
-            <bean class="org.apache.jetspeed.container.session.PortalSessionsManagerImpl"/>
+            <ref bean="org.apache.jetspeed.container.session.PortalSessionsManager"/>
           </entry>
           <entry key="SecurityAccessController">
             <ref bean="org.apache.jetspeed.security.SecurityAccessController"/>
Index: src/webapp/WEB-INF/assembly/ajax-layout.xml
===================================================================
--- src/webapp/WEB-INF/assembly/ajax-layout.xml	(revision 530210)
+++ src/webapp/WEB-INF/assembly/ajax-layout.xml	(working copy)
@@ -493,6 +493,44 @@
         <ref bean="org.apache.jetspeed.page.PageManager"/>        
     </constructor-arg>    
 </bean>
+
+<bean id="AjaxGetUserInformation"
+    class="org.apache.jetspeed.layout.impl.GetUserInformationAction">
+    <constructor-arg index="0">
+        <value>org/apache/jetspeed/layout/ajax-xml/userinfo.vm</value>
+    </constructor-arg>
+    <constructor-arg index="1">
+        <value>org/apache/jetspeed/layout/ajax-xml/error.vm</value>
+    </constructor-arg>
+    <constructor-arg index='2'>    
+        <ref bean="org.apache.jetspeed.security.UserManager"/>        
+    </constructor-arg>
+</bean>
+
+<bean id="AjaxGetUserList"
+    class="org.apache.jetspeed.layout.impl.GetUserListAction">
+    <constructor-arg index="0">
+        <value>org/apache/jetspeed/layout/ajax-xml/userlist.vm</value>
+    </constructor-arg>
+    <constructor-arg index="1">
+        <value>org/apache/jetspeed/layout/ajax-xml/error.vm</value>
+    </constructor-arg>
+    <constructor-arg index='2'>    
+        <ref bean="org.apache.jetspeed.security.UserManager"/>        
+    </constructor-arg>
+    <constructor-arg index='3'>
+        <ref bean="PortalStatistics"/>
+    </constructor-arg>
+    <constructor-arg index='4'>
+        <ref bean="org.apache.jetspeed.container.session.PortalSessionsManager"/>
+    </constructor-arg>
+    <!-- Uncomment this constructor arg to use the SecurityBehavior access restrict -->
+	<!--
+	<constructor-arg index='5'>
+        <ref bean="RolesSecurityBehavior"/>
+    </constructor-arg>
+	-->
+</bean>
     
 <bean id="AjaxActionMap" class="java.util.HashMap">
     <constructor-arg index="0">
@@ -572,6 +610,12 @@
             <entry key="updatelink">
                 <ref bean="AjaxUpdateLink"/>                
             </entry>                                                              
+            <entry key="getuserinfo">
+                <ref bean="AjaxGetUserInformation"/>                
+            </entry>
+            <entry key="getuserlist">
+                <ref bean="AjaxGetUserList"/>                
+            </entry>
         </map>
     </constructor-arg>    
 </bean>    
Index: src/webapp/WEB-INF/assembly/security-managers.xml
===================================================================
--- src/webapp/WEB-INF/assembly/security-managers.xml	(revision 530210)
+++ src/webapp/WEB-INF/assembly/security-managers.xml	(working copy)
@@ -39,6 +39,10 @@
   	   <constructor-arg ><ref bean="org.apache.jetspeed.security.SecurityProvider"/></constructor-arg>   
   </bean>
   
+  <!-- Security: Session Manager -->
+  <bean id="org.apache.jetspeed.container.session.PortalSessionsManager" 
+  	   class="org.apache.jetspeed.container.session.PortalSessionsManagerImpl"  />
+    
   <!-- Security: Permission Manager -->
   <bean id="org.apache.jetspeed.security.impl.PermissionManagerImpl" 
   	   class="org.apache.jetspeed.security.impl.PermissionManagerImpl"  />
Index: jetspeed-api/src/java/org/apache/jetspeed/statistics/UserStats.java
===================================================================
--- jetspeed-api/src/java/org/apache/jetspeed/statistics/UserStats.java	(revision 530210)
+++ jetspeed-api/src/java/org/apache/jetspeed/statistics/UserStats.java	(working copy)
@@ -17,6 +17,8 @@
 package org.apache.jetspeed.statistics;
 
 import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 
 /**
  * UserStats
@@ -34,5 +36,11 @@
 
     public void setNumberOfSession(int number);
 
-    public void setUsername(String username);
+    public void setUsername(String username);
+    
+    public void setInetAddress(InetAddress inetAddress);    
+
+    public InetAddress getInetAddress();
+    
+    public void setInetAddressFromIp(String ip) throws UnknownHostException;
 }
Index: jetspeed-api/src/java/org/apache/jetspeed/container/session/PortalSessionsManager.java
===================================================================
--- jetspeed-api/src/java/org/apache/jetspeed/container/session/PortalSessionsManager.java	(revision 530210)
+++ jetspeed-api/src/java/org/apache/jetspeed/container/session/PortalSessionsManager.java	(working copy)
@@ -36,4 +36,9 @@
     void sessionWillPassivate(PortletApplicationSessionMonitor pasm);    
     void sessionDidActivate(PortletApplicationSessionMonitor pasm);    
     void sessionDestroyed(PortletApplicationSessionMonitor pasm);    
+    /**
+     * Returns the number of current sessions. Used to track the number guest users in portal.
+     * @return Number of currently created sessions in the registry
+     */
+    int sessionCount();
 }
