Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Session Listeners Questions

 
Edmund Yong
Ranch Hand
Posts: 164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Consider the following classes:

public class Dog implements HttpSessionBindingListener,
Serializable {

private String breed;

public Dog(String breed) {
this.breed = breed;
}

public String getBreed() {
return breed;
}

public void valueBound(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("Value Bound: " + name + ": " + value);
}

public void valueUnbound(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("Value Unbound: " + name + ": " + value);
}

public String toString() {
return breed;
}
}

public class BeerAttributeListener implements HttpSessionAttributeListener {

public void attributeAdded(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("Attribute added: " + name + ": " + value);
}

public void attributeRemoved(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("Attribute removed: " + name + ": " + value);
}

public void attributeReplaced(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("Attribute replaced: " + name + ": " + value);
}
}

public class ListenerTester extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType("text/html");
HttpSession session = request.getSession();
session.setAttribute("foo", new Dog("Beagle"));
session.setAttribute("foo", new Dog("Great Dane"));
session.setAttribute("foo", new String("z"));
session.removeAttribute("foo");

PrintWriter out = response.getWriter();
out.println("done");
}
}

When the servlet is called, this is what is logged:

Value Bound: foo: Beagle
Attribute added: foo: Beagle
Value Bound: foo: Great Dane
Value Unbound: foo: null
Attribute replaced: foo: Great Dane
Value Unbound: foo: null
Attribute replaced: foo: Great Dane
Attribute removed: foo: z

My questions:
(1) Why is the "Value Unbound" null in line 4 and 6? Shouldn't they be "Beagle" and "Great Dane" respectively?
(2) Why is "Attribute replaced" in line 5 "Great Dane"? Shouldn't it be "Beagle", which is the value replaced?
 
David Bridgewater
author
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Edmund...

I tried out your code, and replicated your findings - they surprise me too.

On the attributeReplaced() question - I always thought that the event passed into this method yields the old name of the attribute (through event.getValue()). The API documentation for HttpSessionBindingEvent.getValue() (J2EE 1.4) backs me up on this:

"Returns the value of the attribute that has been added, removed or replaced. If the attribute was added (or bound), this is the value of the attribute. If the attrubute was removed (or unbound), this is the value of the removed attribute. If the attribute was replaced, this is the old value of the attribute."

Indeed, if you try your code with request attributes, then you get "Beagle" instead of "Great Dane". So I would say that this is a container bug. What are you using? I found this to be a problem with Tomcat 5.0.28 and Tomcat 5.5.

On the valueUnbound() question - I'm less sure. The API documentation doesn't properly address this, I don't think (i.e. what the HttpSessionBindingEvent should hold going into the valueUnbound() method). I guess I would never have thought of using the event passed to valueUnbound() to determine the old value of the attribute - because you are within a method of the object which represents the old value (i.e. you can use this directly). Does that make sense?

Thanks for an interesting post!

Best,

David.
 
Edmund Yong
Ranch Hand
Posts: 164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi David,

I am using Tomcat 5.5.9. For the attribute part, it does look like a bug. I searched the bug database in the Tomcat website, but I did find it.

For the binding listener part, if I use this.breed instead of event.getValue(), then it works as expected. I think there is also a bug with event.getValue().
 
nagaraj reddy
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello Yong,


Can u Explain your code...

How the attributeAdded() and attributeReplaced() methods in BeerAttributeListener Class are calling.



Any explanation is appreciated..
 
David Bridgewater
author
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi...

Think I can explain that on Edmund's behalf - BeerAttributeListener is simply registered as a listener in the deployment descriptor.

<listener>
<listener-class>BeerAttributeListener</listener-class>
</listener>

Best,

David.
 
Vishnu Prakash
Ranch Hand
Posts: 1026
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
public class Dog implements HttpSessionBindingListener {

public void valueBound(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("Value Bound: " + name + ": " + value);
call();
}

public void valueUnbound(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = this.breed;
System.out.println("Value Unbound: " + name + ": " + value);
call();
}
public void call() {
System.out.println(" call method: " + this.breed);

}

private String breed;

public Dog(String breed) {
this.breed = breed;
System.out.println("Current Object: " + this.breed);
}

public String getBreed() {
return breed;
}

public String toString() {
return breed;
}
}

Output

urrent Object: Beagle
Value Bound: foo: Beagle
call method: Beagle
Attribute added: foo: Beagle

Current Object: Great Dane
Value Bound: foo: Great Dane
call method: Great Dane
-------------------------------------
Value Unbound: foo: Beagle
call method: Beagle
--------------------------------------
Attribute replaced: foo: Great Dane
Value Unbound: foo: Great Dane
call method: Great Dane
Attribute replaced: foo: Great Dane
Attribute removed: foo: z


David's Ans:
because you are within a method of the object which represents the old value (i.e. you can use this directly).

Question:
I couldn't understand how [ Value Unbound ] is producing [ Beagle ] as the result with [ this.breed ] in the Unbound method. Because the current object is Great Dane in this case.

Can any one please explain How am I getting the old values.
 
Vishnu Prakash
Ranch Hand
Posts: 1026
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Any one interested in answering this Q.
 
David Bridgewater
author
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Vishnu...

If you are running the original ListenerTester code, then I think this is what happens. Here are the relevant lines from ListenerTester:

21: session.setAttribute("foo", new Dog("Beagle"));
22: session.setAttribute("foo", new Dog("Great Dane"));
23: session.setAttribute("foo", new String("z"));

At 21, "foo" is set with a new instance of Dog (breed Beagle). valueBound() is called on this Beagle instance.

At 22, "foo" is reset with another new instance of Dog (breed Great Dane).
valueBound() is called on this new Great Dane instance (this.breed == Great Dane)
valueUnbound() is called on the previous Beagle instance (this.breed == Beagle)

At 23, "foo" is set up as a String, not a Dog.
valueUnbound() is called on the Great Dane instance (this.breed == Great Dane).

Please let me know if you agree with this!

Best,

David.
 
Vishnu Prakash
Ranch Hand
Posts: 1026
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

valueUnbound() is called on the previous Beagle instance (this.breed == Beagle)


How this is happening. Because the first step will be "Great Dane" being passed as the parameter to the Dog class which will set instance variable "breed" with "Great Dane".

Second valueBound() will be called which produces the result of "Great Dane" and I also call the method "call()" to confirm the current instance value of "breed" is "Great Dane"

Only in the 3rd step valueUnbound() is called which use "this.breed". Here the result should be "Great Dane" but how we are getting Beagle
 
David Bridgewater
author
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Vishnu:

"Only in the 3rd step valueUnbound() is called which use "this.breed". Here the result should be "Great Dane" but how we are getting Beagle"

There are two, separate Dog objects. The Dog objects themselves are also separate HttpSessionBindingListeners.

Maybe you are thinking that the valueBound()/valueUnbound() methods are being called all on the same object?

Best,

David.
 
Gouri Bargi
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

I checked some tomcat 5.5.9 code for this. There is a org.apache.catalina.session.StandardSession class which is implementing the HttpSession interface. Through a facade, the setAttribute() is being called on this class. Here is the relevant part of code in the setAttribute method:


while calling the constructor for HttpSessionBindingEvent for call to valueUnbound,

the object value is not passed, so the value in unbound is always null. This is why the valueUnbound in line 4 and 6 of the original code is null.

While calling attributeReplaced,


this (event == null) check means the old event instance with the new value (used in call to valueBound) is being used. This does seem to be a bug in Tomcat 5.5.9.

- Gouri
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic