servlet problems with session attributes

P

Pep

I have a servlet application running in Tomcat that uses jsp forms and java
classes. I use session attributes to to preserve data across the session
and to comunicate across servlet objects.

One of the server attributes that I set is a ArrayList containing the
results of a mysql select statement.

No matter what I do I cannot clear the ArrayList contents without restarting
the Tomcat container!

I have removed the session attribute that contains the ArrayList in the form
that processes the container. I dump the session attribute names when I
re-enter the search form and there is no session attribute for the
ArrayList, yet when I execute a search operation I end up with the previous
ArrayList with the new search results appended to the end!

I even invalidate the session when I execute a logout in the my application
which does clear everything but when I log back in and do a search the same
thing happens and I end up with the new search results tacked to the end fo
the previous ArrayList!

Worse, if I login to a separate concurrent session using a different browser
and do a search, the same thing happens and I end up with the results
appended to the end of the list that was created in another users session!

The only way I can clear this ArrayList is to restart the Tomcat container!

Help,
Pep.
 
R

Robert Klemme

Pep said:
I have a servlet application running in Tomcat that uses jsp forms
and java classes. I use session attributes to to preserve data across
the session and to comunicate across servlet objects.

One of the server attributes that I set is a ArrayList containing the
results of a mysql select statement.

No matter what I do I cannot clear the ArrayList contents without
restarting the Tomcat container!

I have removed the session attribute that contains the ArrayList in
the form that processes the container. I dump the session attribute
names when I re-enter the search form and there is no session
attribute for the ArrayList, yet when I execute a search operation I
end up with the previous ArrayList with the new search results
appended to the end!

I even invalidate the session when I execute a logout in the my
application which does clear everything but when I log back in and do
a search the same thing happens and I end up with the new search
results tacked to the end fo the previous ArrayList!

Worse, if I login to a separate concurrent session using a different
browser and do a search, the same thing happens and I end up with the
results appended to the end of the list that was created in another
users session!

The only way I can clear this ArrayList is to restart the Tomcat
container!

Help,
Pep.

Probably the problem is not in your web app but in the code that reads
results from the DB. Maybe someone declared a static or non static member
and returns a reference to the same instance every time data is read from
the db.

Kind regards

robert
 
A

Andrea Desole

Pep said:
I have a servlet application running in Tomcat that uses jsp forms and java
classes. I use session attributes to to preserve data across the session
and to comunicate across servlet objects.

One of the server attributes that I set is a ArrayList containing the
results of a mysql select statement.

No matter what I do I cannot clear the ArrayList contents without restarting
the Tomcat container!

I have removed the session attribute that contains the ArrayList in the form
that processes the container. I dump the session attribute names when I
re-enter the search form and there is no session attribute for the
ArrayList, yet when I execute a search operation I end up with the previous
ArrayList with the new search results appended to the end!

I even invalidate the session when I execute a logout in the my application
which does clear everything but when I log back in and do a search the same
thing happens and I end up with the new search results tacked to the end fo
the previous ArrayList!

Worse, if I login to a separate concurrent session using a different browser
and do a search, the same thing happens and I end up with the results
appended to the end of the list that was created in another users session!

The only way I can clear this ArrayList is to restart the Tomcat container!

It sounds too strange to be a Tomcat bug. It's always possible, of
course, but my first guess in these cases is always an error in the
code, unless you are using other frameworks besides plain servlets and
jsps. Tomcat is usually quite stable.
It's not really clear to me how your code works. The biggest question
probably is related to how your search works, and the relationship with
these session attributes. What I would suggest is to take your code,
remove what you don't need (like all the sql queries), make it as simple
as possible, and post it here. If I understand correctly it should be
one or two jsps and one or two servlets. It's not unlikely that, while
you are doing that, you will find the cause of your problem.
 
P

Pep

Robert said:
Probably the problem is not in your web app but in the code that reads
results from the DB. Maybe someone declared a static or non static member
and returns a reference to the same instance every time data is read from
the db.

Kind regards

robert

I have gone back over the code to check for static variables as I have
fallen foul of that in the past and have not found any. However a further
scan would not be to costly and I concentrated on the ArrayList declaration
so it is possible there is something lower in the code where I actually
read the database.

That someone would be me if it has been done as I am the only coder on this
project :)

Cheers,
Pep.
 
P

Pep

Andrea said:
It sounds too strange to be a Tomcat bug. It's always possible, of
course, but my first guess in these cases is always an error in the
code, unless you are using other frameworks besides plain servlets and
jsps. Tomcat is usually quite stable.
It's not really clear to me how your code works. The biggest question
probably is related to how your search works, and the relationship with
these session attributes. What I would suggest is to take your code,
remove what you don't need (like all the sql queries), make it as simple
as possible, and post it here. If I understand correctly it should be
one or two jsps and one or two servlets. It's not unlikely that, while
you are doing that, you will find the cause of your problem.

I am more than happy to accept that it is my code that is at fault rather
than Tomcat.

There are no other frameworks involved here so I did not expect these sort
of errors.

I will have to isolate the servlet and jsp's that are invloved in this part
of the system to be able to send them to this ng. As you say I may find
the problem in doing that.

More to follow ...

Cheers,
Pep.
 
R

Robert Klemme

Pep said:
I have gone back over the code to check for static variables as I have
fallen foul of that in the past and have not found any. However a
further scan would not be to costly and I concentrated on the
ArrayList declaration so it is possible there is something lower in
the code where I actually read the database.

That someone would be me if it has been done as I am the only coder
on this project :)

LOL An easy check would be to wrap your method that returns the array list
with another method that copies list contents to a newly created list and
clears the original...

robert
 
P

Pep

Andrea Desole wrote:

It's not really clear to me how your code works. The biggest question
probably is related to how your search works, and the relationship with
these session attributes. What I would suggest is to take your code,
remove what you don't need (like all the sql queries), make it as simple
as possible, and post it here. If I understand correctly it should be
one or two jsps and one or two servlets. It's not unlikely that, while
you are doing that, you will find the cause of your problem.

Unfortunately isolating the code did not solve the problem for me.

So you need a table in the mysql database called t_Agent that has the
FirstName and LastName columns, varchar(32) will do for these. My current
table has 7 users all with the surname of Smith.

If you start with PEPagents.jsp and fill in a search string such as Smith in
the surname and press the search button you will get passed to the search
results form with correct list of users.

If you then go back in the browser and execute the search again you will end
up with a list that is twice the size of the original list and the entries
will be duplicated such that the original list has been appended with the
same list again. This happens repeatedly.

If you then close the browser and start all over again, the same thing will
happen in that the list will keep grwoing in size by appending the search
results to the end of the previous list.

If you open another browser and therefore a new session you end up with the
extended list in the new browser!

I do not know what is causing this or what to do to prevent this. The only
way to clear the list os to restart the Tomcat container.

The main servlet
================
package core;

// Import the standard java classes
import java.io.*;
import java.util.*;
// Import the servlet classes
import javax.servlet.*;
import javax.servlet.http.*;
// Import the java sql classes
import java.sql.*;
// Import the packages own classes
import core.beans.Pep;

public class PEPagentEditor extends HttpServlet
{
private Pep agentObject;
private String errorString;
private ArrayList agentArray = new ArrayList();

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}

public void doPost(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException
{
errorString = "";

// Get the session object
HttpSession session = request.getSession();

Pep agentEditor = new Pep();

boolean searchingForUsers = (request.getParameter("buttonSearch") !=
null);
boolean creatingNewUsers = (request.getParameter("buttonNew") != null);
String userFirstName = request.getParameter("userFirstName");

if (userFirstName != null)
// Set the agent editor first name
{
agentEditor.setFirstName(userFirstName);
}

String userLastName = request.getParameter("userLastName");

if (userLastName != null)
// Set the agent editor last name
{
agentEditor.setLastName(userLastName);
}

searchForUser(agentEditor);

if (errorString.equals("") && (agentArray.size() != 0))
// No errors so display the users
{
session.setAttribute("agentArray", agentArray);

getServletConfig().getServletContext().getRequestDispatcher("/PEPsearchResults.jsp").forward(request,
response);
}

if (!errorString.equals(""))
// Guess a error occurred
{
// Add the error string
session.setAttribute("errorString", errorString);
// Remove the agent array so that we don't recursively fill it up.
session.removeAttribute("agentArray");

// Branch to the login page, because we have to go somewhere

getServletConfig().getServletContext().getRequestDispatcher("/PEPagents.jsp").forward(request,
response);
}

}

private void searchForUser(Pep agentEditor)
{

try
{
// Create the database url which is <driver type:database
type://hostname/database name>
String databaseUrl = "jdbc:mysql://localhost/TestDB";
// Load the database driver
Class.forName("com.mysql.jdbc.Driver");
// Create the datbase connection
Connection sqlConnection = DriverManager.getConnection(databaseUrl,
"user", "password");
// Create the sql statement
Statement sqlStatment = sqlConnection.createStatement ();
// Execute the query, storing the results in a result
String sqlQuery = "select LastName, FirstName from t_Agent where LastName
like '"
+
agentEditor.getLastName()
+
"%'";
ResultSet sqlResultSet = sqlStatment.executeQuery(sqlQuery);

int numberOfColumns = sqlResultSet.getMetaData().getColumnCount();

if (numberOfColumns != 2)
// There is an error here as we should only get 2 columns
{
errorString += "<p>Login was unsuccessful because a incorrect number of
columns received!";
}
else
{

while (sqlResultSet.next())
// handle all the rows returned
{
Pep agentFound = new Pep();
agentFound.setLastName(sqlResultSet.getString(1));
agentFound.setFirstName(sqlResultSet.getString(2));
agentArray.add(agentFound);
}

}

sqlResultSet.close();
sqlStatment.close();
sqlConnection.close();
}
catch(ClassNotFoundException exception)
{
errorString += "java class not found error: " + exception.getMessage();
}
catch(SQLException sqlException)
{

while (sqlException != null)
{
errorString += "<p>SQL Exception: " + sqlException.getMessage();
sqlException = sqlException.getNextException ();
}

}

}

}

the main jsp
============
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- Handle the session attributes -->
<%
String errorString = (String)session.getAttribute("errorString");
session.removeAttribute("agentArray");
%>
<HTML>
<BODY BGCOLOR="#FDF5E6">
<CENTER>
<FORM method=POST ACTION=/servlet/core.PEPagentEditor>
Surname:
<INPUT TYPE="TEXT" NAME="userLastName" VALUE="">
<P>
Christian:
<INPUT TYPE="TEXT" NAME="userFirstName" VALUE="">
<p>
<input type=SUBMIT name=buttonSearch value="SEARCH">
<p>
<input type=SUBMIT name=buttonNew value="NEW">
</FORM>
</CENTER>
<p> <% if (errorString != null){ %>
<p> <%= errorString %>
<p> <% } %>
<p><b><u>Session attributes</u></b>
<%
java.util.Enumeration attributeNames = session.getAttributeNames();

while (attributeNames.hasMoreElements())
{
String attributeName = (String)attributeNames.nextElement();
%>
<p> <%= attributeName %>
<%
}
%>
</BODY>
</HTML>
<!-- Clear up the session attributes -->
<%
session.removeAttribute("errorString");
// It is possible that this already exists if the user has pressed a back
key in the browser so we need to remove it
session.removeAttribute("agentArray");
%>

The search results jsp
======================
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<jsp:useBean id="agentArray" scope="session" class="java.util.ArrayList"/>
<!-- Handle the session attributes -->
<%
String errorString = (String)session.getAttribute("errorString");
%>
<HTML>
<BODY BGCOLOR="#FDF5E6">
<CENTER>
<FORM method=POST ACTION="/servlet/core.PEPagentSelectedResult">

<SELECT name=agentSelected size=1>
<% for (int arrayElement = 0; arrayElement < agentArray.size();
arrayElement++) {%>
<% core.beans.Pep agentFound =
(core.beans.Pep)agentArray.get(arrayElement); %>
<OPTION value= <%= arrayElement %> > <%= agentFound.getLastName() %>
<%= agentFound.getFirstName() %>
<% } %>
</SELECT>
<P>
<INPUT TYPE="SUBMIT" VALUE="OPEN" NAME=openButton>
</FORM>
</CENTER>
<p> <% if (errorString != null){ %>
<p> <%= errorString %>
<p> <% } %>
<p><b><u>Session attributes</u></b>
<%
java.util.Enumeration attributeNames = session.getAttributeNames();

while (attributeNames.hasMoreElements())
{
String attributeName = (String)attributeNames.nextElement();
%>
<p> <%= attributeName %>
<%
}
%>
</BODY>
</HTML>
<!-- Clear up the session attributes -->
<%
session.removeAttribute("errorString");
%>

The bean
========
package core.beans;

public class Pep
{
private String lastName;
private String firstName;

public Pep()
{
setLastName("");
setFirstName("");
}

public Pep(
String lastName,
String firstName
)
{
setLastName(lastName);
setFirstName(firstName);
}

public void setLastName(String lastName)
{
this.lastName = lastName;
}

public String getLastName()
{
return(lastName);
}

public void setFirstName(String firstName)
{
this.firstName = firstName;
}

public String getFirstName()
{
return(firstName);
}

}
 
P

Pep

Robert said:
LOL An easy check would be to wrap your method that returns the array list
with another method that copies list contents to a newly created list and
clears the original...

robert

I have just posted the code in response to Andrea's post and as you can see
I start out with a new ArrayList each time the servlet is enterred and I
clear the session attribute before it is enterred but this does not solve
the problem.

It's behaving as though the ArrayList is of container scope?

I checked to see how many rows were being retrieved in the sql statement
each time the servlet is executed and sure enough it is only the number I
expect and also the size of the ArrayList before being set as the session
attribute is as expected?

Cheers,
Pep.
 
R

Robert Klemme

Pep said:
I have just posted the code in response to Andrea's post and as you
can see I start out with a new ArrayList each time the servlet is
enterred

Definitely not! You have a new ArrayList every time the servlet is
instantiated. That's something different and it usually happens only once
during tomcat's life cycle. Make it a local variable (i.e. in doPost()).

You probably need to dig a bit deeper into Servlet documentation
(tutorial)...

Kind regards

robert
 
P

Pep

Robert Klemme wrote:

Definitely not! You have a new ArrayList every time the servlet is
instantiated. That's something different and it usually happens only once
during tomcat's life cycle. Make it a local variable (i.e. in doPost()).

You probably need to dig a bit deeper into Servlet documentation
(tutorial)...

Kind regards

robert

Thanks very much for being kind there :)

I have solved the problem with that little pointer form you and have
addressed further examples of this problem in my code suite because of it.

It's a pity as it means that I need to use local variables and pass them as
function parameters within the same class instead of using class variables.

Ho hum, so in effect class variables are actually container variables?

I will definitely go back to reading the manuals regarding this area :)

Cheers,
Pep.
 
V

Viator

A global variable like your 'agentArray' is associated with the
instance of the servlet not the request. You said in your previous
message that it is instantiated every time the servlet is entered but
the fact is that the servlet is entered in doXXXX methods rather than
in constructor because server does not (or might not) create one
servlet instance per request. Actually many requests are served by same
instance of servlet and this is how J2EE works. One more thing is that
the class variables in servlets are not container variables by any
means but they are class variables only. The only thing you need to
understand is that one request for the servlet is not necessarily going
to create an instance of the servlet. This is true of course if you are
not implementing SingleThreadModel interface.

Amit :)
 
P

Pep

Viator said:
A global variable like your 'agentArray' is associated with the
instance of the servlet not the request. You said in your previous
message that it is instantiated every time the servlet is entered but
the fact is that the servlet is entered in doXXXX methods rather than
in constructor because server does not (or might not) create one
servlet instance per request. Actually many requests are served by same
instance of servlet and this is how J2EE works. One more thing is that
the class variables in servlets are not container variables by any
means but they are class variables only. The only thing you need to
understand is that one request for the servlet is not necessarily going
to create an instance of the servlet. This is true of course if you are
not implementing SingleThreadModel interface.

Amit :)

Yep got it, that was my clumsy way of saying that I now understand that
class variables are not instantiated once per call to the servlet :)
 
R

Robert Klemme

Viator said:
A global variable like your 'agentArray' is associated with the
instance of the servlet not the request.

It's not directly a global variable in the sense of the Java language.
It's simply an instance variable (or member).
You said in your previous
message that it is instantiated every time the servlet is entered but
the fact is that the servlet is entered in doXXXX methods rather than
in constructor because server does not (or might not) create one
servlet instance per request.

I guess, the container is actually allowed to create a servlet instance
per request - although that would be inefficient.
Actually many requests are served by
same instance of servlet and this is how J2EE works.
Right.

One more thing
is that the class variables in servlets are not container variables
by any means but they are class variables only.

It's not a class variable, it's an instance variable!
The only thing you
need to understand is that one request for the servlet is not
necessarily going to create an instance of the servlet. This is true
of course if you are not implementing SingleThreadModel interface.

Even then. The container is only required to ensure that no more than one
thread at a time enters one of the doX methods of a single thread model
servlet. Subsequent requests may be routed through the same servlet
nevertheless.

Use instance variables in servlets only for things that should have the
same life cycle as the servlet instance. Everything else must be done
with local variables. IMHO servlets should not be complex anyway so if
you need more complex calculations you can for example resort to command
pattern, i.e., delegate the real work to another class's instance that is
created per request.

Folks, know your tools! The servlet spec isn't really unreadable. Just
spend the time to read and understand. Will save you a lot of hassle...

Kind regards

robert
 
P

Pep

Robert Klemme wrote:

Folks, know your tools! The servlet spec isn't really unreadable. Just
spend the time to read and understand. Will save you a lot of hassle...

Kind regards

robert

Well I will certainly be doing more reading on this littel puppy now that I
fell foul of that :)
 
V

Viator

Thanks for correcting me on SingleThreadModel.
Regarding class variables; they are class variable only while instance
variables are instance variable.
I admit that I should have written instance variable there.
Thanks again.
Amit :)
 
J

Jimi Hullegård

Pep said:
Robert Klemme wrote:



Thanks very much for being kind there :)

I have solved the problem with that little pointer form you and have
addressed further examples of this problem in my code suite because of it.

It's a pity as it means that I need to use local variables and pass them
as
function parameters within the same class instead of using class
variables.

Maybe you should look into EJB (Enterprise Java Beans), and session beans in
particular.

/Jimi
 
P

Pep

Jimi said:
Maybe you should look into EJB (Enterprise Java Beans), and session beans
in particular.

/Jimi

It's not really a large enough system to justify using EJB. It will result
in around 25 forms and 35 servlets with 6 beans, so Tomcat is more than
enough though I may extend to struts and hibernate later.

Cheers,
Pep.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,113
Latest member
Vinay KumarNevatia
Top