In the client/server and Web application world, a session can be considered as a series of related interactions between a single client and the server that take place over a period of time. For example, during a visit to an Internet shopping site, a session could be the series of transactions that a user makes while adding items to a shopping cart. The session may consist of multiple requests to the same servlet, or of requests to many different resources on the same web site. While HTTP is a stateless protocol, the web server does not automatically know how to associate a request with a particular session. Web applications have used several techniques to get around the stateless operations of HTTP:
The Java Servlet API provides the javax.servlet.http.HttpSession
interface to implement session handling
in Java server programming. JSPs and servlets store the session ID on the client either by sending a cookie, which is the default
mechanism, or by rewriting the URL to append the session ID to each link that is needed. Using this session ID, JSPs and servlets
can obtain the associated Java session object to retrieve or update information based on the user request. If the client does not support
cookies and URL rewriting is not enabled, no session ID is returned to the server on a request, which the server then perceives as
a new session. A session exists on the server until it is timed out (or invalidated) or the server is stopped. Users can
effectively end a session by closing their browsers. Therefore, it is considered a good practice to enable the application
to store long-term data, and rely on session tracking for short-term processes, such as determining whether a user has logged in.
To store data with the session, you use the setAttribute() method on the session object. Likewise, you use the getAttribute() method to retrieve data. For example, if you have a String object str, you bind it to the session with
session.setAttribute("some-unique-key", str);
To retrieve the object on a subsequent JSP or servlet, you use
String newstr = (String) session.getAttribute("some-unique-key");
where the new object is cast to the appropriate type.
With JSP, each page is within the session context, which means that the session object is available for use on the page without having to declare it. With servlets, you can get the session object from the request object's getSession() method:
HttpSession session = request.getSession();
Other useful session methods include
String getId()
, which returns the unique session IDlong getCreateTime()
, which returns the time in milliseconds that the
session was establishedlong getLastAccessedTime()
, which returns the last time a request was sent
that was associated with this sessionSeveral TransformationBeans require the use of a servlet or JSP session context in order to provide their expected functionality, such as drill-down features, table scrolling, or tree node expansion. In some cases, the underlying model must be cached in the session object to determine whether the model has already been created so as to maintain the state of the TransformationBean visual component.
If you are using a TransformationBean that requires a session context in a servlet, instantiate the object that you need to cache, then add it to the session object. For example, consider the TreeView bean when it is used in conjunction with the LevelTreeInterface:
LevelTreeInterface lt = (LevelTreeInterface)session.getAttribute("tree"); if (levelTreeModel == null) { lt = (LevelTreeInterface)com.sas.servlet.util.Util.newInstance(rocf, connection, LevelTreeInterface.class); lt.setDataSet("sasuser.mydataset"); // additional methods here... session.setAttribute("tree", lt); }
The Java code explicitly tries to retrieve a LevelTreeInterface from the session object, and if one is not found, a new object is instantiated. The actual TreeView TransformationBean, then, simply displays the current state of the LevelTreeInterface model.
To make use of the session context on a JSP page, you can use either the <jsp:useBean> action
or the appropriate SAS custom tag and set the scope attribute value to session
. For example,
a MDTable can be implemented using a <jsp:useBean> action:
<jsp:useBean id="tableObj" class="com.sas.servlet.beans.mddbtable.html.MDTable" scope="session">The underlying MDDB table and the user's location or drill path are all cached with
scope="session"
as part of the MDTable
to enable the object to maintain state between user requests of the same page. Likewise, this example
shows how you can implement the Table bean with the SAS custom tag:
<sasads:Table id="table" model="dataSet" borderWidth="1" widthPercentage="50" cellSpacing="2" cellPadding="2" useColumnHeadings="true" maxRows="10" maxColumns="10" scope="session" > <sasads:NavigationBar formAction="browseDisplay.htm" /> </sasads:Table>
Note that the underlying dataset model is cached in the session, which enables the NavigationBar to maintain the record pointer and scroll through the table.
IMPORTANT: You must take care to remember that,
if your application includes several pages that store objects in the session cache, all of those
object names must be unique. If pages instantiate objects of the same name but from different
pages, the results are unpredictable. For example, if you create one JSP that uses an MDTable
named tbl
and then copy the code from that page to a second JSP and do not
rename the object, viewing the pages in sequence will result in the display of incorrect data.
This consequence is not a limitation of TransformationBeans
or InformationBeans, but rather the behavior expected when using the session context.
While session management is a great tool, your applications need to make
sure that the clients are passing a session ID appropriately, even if some users turn off cookie support
in their browsers. Fortunately, the encodeURL()
method on the response object adds the ability to
determine whether or not a user has cookies turned on. A call to the
method encodes the specified URL by including the session ID in it,
or,
if encoding is not needed, returns the URL unchanged. For example, if
the browser supports cookies, or session tracking is turned off, URL
encoding is unnecessary, and the string passes through unchanged.
The servlet container or application server you use determines what parameter name is passed as the session ID and what value that parameter is assigned. For example, the BEA WebLogic server might send
http://myapp.myserver.com/dir/page.jsp?AppId=345EA7B166712CC
where the default session parameter name is AppId
. With JRun 3.0, the default is jsessionid
.
The name of the parameter is typically configurable on the server. Remember to use a session ID parameter name that
would not conflict with any of the other parameters that your application might pass.
response.encodeURL()
All links, redirections, and <FORM> actions that are used in your JSP pages must
be encoded to include the session ID as part of the URL.
you only need to add URL encoding to links that direct users to other pages in a web application. For example,
in a shopping cart application, a link to shopcart.jsp
could be URL-encoded, while a link to a standard
Web document such as http://www.sas.com
does not require encoding.
For example, the URL that is specified in the ACTION attribute of a <FORM> tag is coded as
<FORM ACTION="<%= response.encodeURL("foo.htm") %>" METHOD="POST">
Note that if you employ URL rewriting, the METHOD attribute of the <FORM> tag must be set to "POST".
Links to a dynamic page such as a JSP are coded as
<A HREF="<%= response.encodeURL("foo.htm") %>">Link Here</A>
The encodeURL()
method adds the sessionID to the list of parameters only if it
detects that the user has turned off cookies on the browser. Otherwise, nothing happens to the URL string.
You do not have to escape the quotes inside the method, even though you are passing a
literal inside of an expression that happens to be contained within quotes. It's JSP magic.
Links that contain HTTP parameters can also be URL-encoded. For example, the following code
<A HREF="<%=response.encodeURL("foo.jsp?id=120&chkval=300")%>">Link</A>
would produce HTML in a browser with cookies disabled that looks like
<A HREF="foo.jsp?id=120&chkval=300&sessionid=1263478235845">Link</A>
You must also encode URLs that redirect the response. For example,
<%= response.sendRedirect( response.encodeRedirectURL("foo.htm") ) %>
Note that when you send a redirected page using the response.sendRedirect()
method,
you must use the encodeRedirectURL()
method instead.
The following snippets of code demonstrate session management with encoded URLs. Note that to see URL rewriting in action, you must turn off your browser's cookie support. (Remember to turn it back on again when you finish to see the page work with cookies.)
Page 1: HTML Form in a file named FormTest.jsp
The request object methods that appear at the bottom of this code are used to identify how the session
information was passed back to the server from the client.
<HTML> <BODY> <FORM ACTION="<%= response.encodeURL("FormTest2.htm") %>" METHOD="POST"> Enter your name: <INPUT TYPE="text" NAME="myname" SIZE="32"> <INPUT TYPE="submit" VALUE="OK"> </FORM> <PRE> isRequestedSessionIdFromCookie() = <%=request.isRequestedSessionIdFromCookie()%> isRequestedSessionIdFromURL() = <%=request.isRequestedSessionIdFromURL()%> isRequestedSessionIdValid() = <%=request.isRequestedSessionIdValid()%> </PRE> </BODY> </HTML>
Page 2: Results Page in a file named FormTest2.jsp
The page that is displayed as a result of the form action in FormTest.jsp
makes use of several session methods
to demonstrate how you can keep track of session information. The session.setAttribute()
and
session.getAttribute()
methods demonstrate how to store data in and read data from a session object.
<HTML> <HEAD><TITLE>COUNTER TEST PAGE</TITLE></HEAD> <% int count = 1; Integer i = (Integer) session.getAttribute("test.counter.hit"); if (i != null) count = i.intValue() + 1; session.setAttribute("test.counter.hit", new Integer(count)); %> <BODY> <P>Hello, <%= request.getParameter("myname") %> <BR> Your session ID is <%= session.getId() %> <BR> You have hit this page <b><%= count %></b> time(s) during this browser session.</P> <P>Click <A HREF="<%= response.encodeURL("FormTest.htm")%>">here</A> to go back to FormTest.jsp, or <BR> <FORM ACTION="<%= response.encodeURL(request.getRequestURI())%>" METHOD="POST"> <INPUT TYPE="SUBMIT" VALUE=" HIT PAGE AGAIN "> </FORM> <PRE> isRequestedSessionIdFromCookie() = <%=request.isRequestedSessionIdFromCookie()%> isRequestedSessionIdFromURL() = <%=request.isRequestedSessionIdFromURL()%> isRequestedSessionIdValid() = <%=request.isRequestedSessionIdValid()%> </PRE> </BODY> </HTML>
Encoded URLs and TransformationBeans
Several webAF TransformationBeans directly support encoded URLs, including StaticText, MenuItem, MDTable,
and others. Consider the following example that makes use of the StaticText bean:
<html> <body> <p>This example shows static text generated by the Static Text Transformation Bean whose link is URL-encoded.</p> <% // Create a new static text object com.sas.servlet.beans.StaticTextInterface utext = new com.sas.servlet.beans.html.StaticText(); utext.setText("Return to shopping cart."); utext.setURL("apps/shopcart.jsp?id=10"); utext.setEncodedURL( true, response ); utext.write(out); %> </body> </html>
The HTML output, assuming cookies are disabled and the page is returned from a JSP that executes on a JRun server, appears as:
<html> <body> <p>This example shows static text generated by the Static Text Transformation Bean whose link is URL-encoded.</p> <a href="apps/shopcart.jsp?id=10&jsessionid=12345623563623">Return to shopping cart.</a> </body> </html>