Engineering Full Stack Apps with Java and JavaScript
HttpSessionBindingListener interface should be implemented by classes that may be bound into sessions as attributes and if they want to know when they were bound. When an object which implements this interface is bound to a session or unbound from the session, the container will call its valueBound and valueUnbound methods respectively. Since the interface is added by the attributes that are added to the session themselves and cannot listen to any other attributes, you don’t have to mention it in the web.xml file or have the @WebListener annotation.
The valueBound and valueUnbound methods are passed with a HttpSessionBindingEvent event that contains the below important methods:
getName – Name of the attribute added to session.
getValue – Value of the attribute will be this object itself.
GetSession – Current session object.
It also contain the inherited methods from EventObject: getSource() and toString().
HttpSessionBindingEvent ia sent to methods of both objects that implements HttpSessionBindingListener as well as HttpSessionAttributeListener.
Let us understand the HttpSessionBindingListener with a simple example. We will create two objects that implement HttpSessionBindingListener and add them to session to see when the implemented valueBound and valueUnbound methods are called.
First we will create two classes MySessionBindingListenerA and MySessionBindingListenerB that implement HttpSessionBindingListener interface.
MySessionBindingListenerA.java
package com.javajee.listeners;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class MySessionBindingListenerA implements HttpSessionBindingListener {
private int intData;
public MySessionBindingListenerA(int data) {
this.intData = data;
}
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("Inside MySessionBindingListenerA.valueBound");
System.out.println("Attribute name=" + event.getName());
System.out.println("Attribute's intData value="
+ ((MySessionBindingListenerA) event.getValue()).intData);
System.out.println("this.intData value=" + this.intData);
}
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("Inside MySessionBindingListenerA.valueUnbound");
System.out.println("Attribute name=" + event.getName());
System.out.println("Attribute's intData value="
+ ((MySessionBindingListenerA) event.getValue()).intData);
System.out.println("this.intData value=" + this.intData);
}
}
MySessionBindingListenerB.java
package com.javajee.listeners;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class MySessionBindingListenerB implements HttpSessionBindingListener {
private int intData;
public MySessionBindingListenerB(int data) {
this.intData = data;
}
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("Inside MySessionBindingListenerB.valueBound");
System.out.println("Attribute name=" + event.getName());
System.out.println("Attribute's intData value="
+ ((MySessionBindingListenerB) event.getValue()).intData);
System.out.println("this.intData value=" + this.intData);
}
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("Inside MySessionBindingListenerB.valueUnbound");
System.out.println("Attribute name=" + event.getName());
System.out.println("Attribute's intData value="
+ ((MySessionBindingListenerB) event.getValue()).intData);
System.out.println("this.intData value=" + this.intData);
}
}
Now create a test servlet to add objects of these classes into session.
ListenerTest.java
package com.javajee.servlets;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.javajee.listeners.MySessionBindingListenerA;
import com.javajee.listeners.MySessionBindingListenerB;
@WebServlet("/ListenerTest")
public class ListenerTest extends HttpServlet {
private static final long serialVersionUID = 1L;
public ListenerTest() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
MySessionBindingListenerA msblA = new MySessionBindingListenerA(5);
System.out
.println("[ListenerTest] Adding attribute of type MySessionBindingListenerA.");
session.setAttribute("msblA", msblA);
System.out
.println("[ListenerTest] Removing Attribute of type MySessionBindingListenerA.");
session.setAttribute("msblA", null);
MySessionBindingListenerB msblB = new MySessionBindingListenerB(10);
System.out
.println("[ListenerTest] Adding attribute of type MySessionBindingListenerB.");
session.setAttribute("msblB", msblB);
System.out
.println("[ListenerTest] Removing Attribute of type MySessionBindingListenerB.");
session.setAttribute("msblB", null);
}
}
When you execute this servlet, you will get output in the console as:
[ListenerTest] Adding attribute of type MySessionBindingListenerA.
Inside MySessionBindingListenerA.valueBound
Attribute name=msblA
Attribute's intData value=5
this.intData value=5
[ListenerTest] Removing Attribute of type MySessionBindingListenerA.
Inside MySessionBindingListenerA.valueUnbound
Attribute name=msblA
Attribute's intData value=5
this.intData value=5
[ListenerTest] Adding attribute of type MySessionBindingListenerB.
Inside MySessionBindingListenerB.valueBound
Attribute name=msblB
Attribute's intData value=10
this.intData value=10
[ListenerTest] Removing Attribute of type MySessionBindingListenerB.
Inside MySessionBindingListenerB.valueUnbound
Attribute name=msblB
Attribute's intData value=10
this.intData value=10
As you can see from the programs, you have not specified this listener in web.xml file. You have also not used the @WebListener annotation. This is not required as the listener object is being inserted into the session and hence no other way is required to tell container that this is a listener.
What will happen if we explicitly tell container about HttpSessionBindingListener using web.xml or @WebListener annotation? Just add @WebListener annotation to our listener classes MySessionBindingListenerA and MySessionBindingListenerB.
Above program when executed in Apache Tomcat 8, gave below exception in console:
SEVERE: Error configuring application listener of class com.javajee.listeners.MySessionBindingListenerA
java.lang.InstantiationException: com.javajee.listeners.MySessionBindingListenerA
at java.lang.Class.newInstance(Unknown Source)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4642)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
…
SEVERE: Error configuring application listener of class com.javajee.listeners.MySessionBindingListenerB
java.lang.InstantiationException: com.javajee.listeners.MySessionBindingListenerB
at java.lang.Class.newInstance(Unknown Source)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4642)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
In the browser I got a 404 error as the servlet was not loaded at all due to exceptions.
I made a small modification by adding a no-arg constructor and when executed in Apache Tomcat 8, gave below exception in console:
SEVERE: Error configuring application listener of class com.javajee.listeners.MySessionBindingListenerA
java.lang.IllegalAccessException: Class org.apache.catalina.core.DefaultInstanceManager can not access a member of class com.javajee.listeners.MySessionBindingListenerA with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4642)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
…
SEVERE: Error configuring application listener of class com.javajee.listeners.MySessionBindingListenerB
java.lang.IllegalAccessException: Class org.apache.catalina.core.DefaultInstanceManager can not access a member of class com.javajee.listeners.MySessionBindingListenerB with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4642)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
In the browser I got a 404 error as the servlet was not loaded at all due to exceptions.
Finally I removed the @WebListener annotations and could get successful response.
Eclipse Luna Java EE IDE for Web Developers and Apache Tomcat 8.0.18, using Servlet spec 3.1.