I'm trying to list currently online users on a pet project I'm working on. I've found a few ways to do it, but I'm having difficutly getting the one I chose to work properly. The basic idea was to use an HttpSessionBindingListener on the users information to add it to a list in the application scope, and remove it when the session was terminated.

My implementation appears to work and the bind/unbind methods look like this:

public class Player implements HttpSessionBindingListener{
    //Player variables/methods...
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        ServletContext context = event.getSession().getServletContext();
        ArrayList<Player> logins = (ArrayList<Player>) context.getAttribute("logins");
        if(logins==null){
            logins=new ArrayList<Player>();
            context.setAttribute("logins", logins);
        }
        logins.add(this);
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        ServletContext context = event.getSession().getServletContext();
        ArrayList<Player> logins = (ArrayList<Player>) context.getAttribute("logins");
        logins.remove(this);
    }
}

But when I tried to write a custom tag to loop through the online players I get null for the "logins" attribute. My tag implementation looks like this:

import java.util.ArrayList;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

/**
 *
 */
public class ListOnlinePlayers extends SimpleTagSupport {
    private String var;

    /**
     * Called by the container to invoke this tag. The implementation of this
     * method is provided by the tag library developer, and handles all tag
     * processing, body iteration, etc.
     */
    @Override
    public void doTag() throws JspException {
        JspWriter out = getJspContext().getOut();

        try {

            JspFragment f = getJspBody();
            if (f != null) {

                List<Player> players = (List<Player>) getJspContext().getAttribute("logins");
                if(players==null){
                    players = new ArrayList<Player>();
                    getJspContext().setAttribute("logins", players);
                }
                for(Player p : players){
                    getJspContext().setAttribute(var, p);
                    f.invoke(out);
                }
                getJspContext().removeAttribute(var);
            }
        } catch (java.io.IOException ex) {
            throw new JspException("Error in ListAllPlayers tag", ex);
        }
    }

    public void setVar(String var) {
        this.var = var;
    }

}

I can only take away from this that SimpleTagSupport.getJspContext() and/or it's scope are not the same as HttpSessionBindingEvent.getServletContext() and/or it's scope. While debugging both methods looking through the scopes "logins" is created and the Player is added to it correctly, but I cannot find it while debuggnig the tag and searching through the JspContext.

How can I use a global application scope between custom tags/servlet/jsp? Is there something simple I'm missing about the scope rules? Or is there a different context in one or both I need to use for this?

Well, I found a way to get this to work it was a matter of replacing this:
List<Player> players = (List<Player>) getJspContext().getAttribute("logins"); with

               PageContext pc = (PageContext)getJspContext();
               List<Player> players = (List<Player>)pc.getSession().getServletContext().getAttribute("logins");

This may not be the best way to do it, but it does work now any other suggestions still welcome, but I am going to mark as solved.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.