Resources

SAS® AppDev Studio 3.0 Developer's Site

Introduction to Sessions

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

Sessions and TransformationBeans

Several 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.

URL Rewriting

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.

When to Use URL Rewriting with 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.

Examples

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>