460 likes | 553 Views
Understand session management in web applications using cookies, JSP, and HTTP to maintain conversational state across pages. Learn how to use HttpSession, cookies, and session expiration in Java web development. Explore benefits of session lifecycle events.
E N D
COMP 321 Week 9
Overview • Lab 7-1 “Preparing to Build Web Applications” Solution • Session Management • Cookies • JSP
Session Management • HTTP is stateless – each request from the client looks like a new conversation • Web applications need to maintain state across pages (think of browsing Amazon and putting books in your shopping cart) • How can we do this?
Session Management (cont’d) • Stateful EJB • Works, but it’s complicated. Also, requires a full J2EE application server • Database • Also works, but could be slow and is overkill for many applications • HttpSession • This is a nice, lightweight solution. We assign an HttpSession object to each client connection, and use them to maintain conversational state
Session Management (cont’d) • Browser displays form - What type of beer do you like? • Diane submits page with response - dark • Container stores response in Diane’s session, returns another page with another question - What price range? • Diane answers question, submits second page with response • Container stores this answer in session, continues…
Session Management (cont’d) • How can the container remember which client is which? • IP Address? • This does not work because of NAT • HTTPS Security Context? • Would require HTTPS for each connection • Session ID • Container can send unique session ID to each client
Session Management (cont’d) • Cookies are used to store the session ID • Cookies are a name-value pair that the browser stores under a web domain • When subsequent requests are sent to the domain, the cookie data is included: HTTP/1.1 200 OK Set-Cookie: JSESSIONID=0AAB6C8DE415 ... POST /select/selectBeerTaste2.do HTTP/1.1 Host: www.wickedlysmart.com User-Agent: Mozilla/5.0 Cookie: JSESSIONID=0AAB6C8DE415
Session Management (cont’d) • How do we create a session in the servlet? Just ask for one. • How do we get the session object on a subsequent request? // Send a session cookie in the response HttpSession session = request.getSession(); // Get the session for this conversation HttpSession session = request.getSession();
URL Rewriting • Can be used to maintain session state without cookies • Works by appending session information to the end of every link: http://www.wickedlysmart.com/BeerTest.do;jsessionid=0AAB6C8DE415 • Must be done on every page in the application - no static HTML allowed • Must use response.encodeURL() for every URL in the generated pages
Session Expiration • Session times out • Timeout was set in deployment descriptor • Timeout was set by calling setMaxInactiveInterval() • invalidate() was called • Web application goes down
Why Use Cookies? • They survive longer than the session! // Create a new cookie, and return as part of response Cookie cookie = newCookie("username", name); cookie.setMaxAge(30*60); // 30 minutes response.addCookie(cookie); // On next request, find cookie Cookie[] cookies = request.getCookies(); for(Cookie cookie : cookies) { if(cookie.getName().equals("username")) { String username = cookie.getValue(); out.println("Hello, " + username); break; } }
Session Lifecycle Events • Lifecycle – HttpSessionListener • Session created • Session destroyed • Attributes – HttpSessionAttributeListener • Attribute added • Attribute replaced • Attribute removed • Migration – HttpSessionActivationListener • Session about to be passivated • Session has been activated
Session Migration • What happens to ServletContext, ServletConfig, and HttpSession in a clustered (distributed) environment? • Most parts of the web application are duplicated on each VM, but session objects are unique • When a session is needed on a specific VM, it is moved to that VM
Session Migration in Action • Request is sent to VM1, session #123 is created • Next request from same client goes to VM2, servlet asks for session #123 • VM2 sees that session 123 exists in VM1 • Session is passivated in VM1, moved to VM2, and activated there • Servlet execution in VM2 continues normally
Session Listener Example <web-app ...> <listener> <listener-class>com.example.BeerSessionCounter</listener-class> </listener> </web-app> publicclassBeerSessionCounterimplementsHttpSessionListener { staticprivateintactiveSessions; publicstaticintgetActiveSessions() { returnactiveSessions;} publicvoidsessionCreated(HttpSessionEvent event) { activeSessions++; } publicvoidsessionDestroyed(HttpSessionEvent event) { activeSessions--; } }
Attribute Listener Example // Deployment descriptor identical to session listener, except for class name publicclassBeerAttributeListener implementsHttpSessionAttributeListener{ publicvoidattributeAdded(HttpSessionBindingEvent event) { System.out.println("Attr added: " + event.getName() + ": " + event.getValue()); } publicvoidattributeRemoved(HttpSessionBindingEvent event) { System.out.println("Attr removed: " + event.getName() + ": " + event.getValue()); } publicvoidattributeReplaced(HttpSessionBindingEvent event) { System.out.println("Attr replaced: " + event.getName() + ": " + event.getValue()); } }
Attribute Class Events publicclass Dog implementsHttpSessionBindingListener, HttpSessionActivationListener, Serializable { publicvoidvalueBound(HttpSessionBindingEvent event) { // Run some code now that I'm in a session } publicvoidvalueUnbound(HttpSessionBindingEvent event) { // Run some code now that I'm not part of a session } publicvoidsessionWillPassivate(HttpSessionEvent event) { // Save my non-serializable fields somehow } publicvoidsessionDidActivate(HttpSessionEvent event) { // Restore whatever I did in sessionWillPassivate } }
JSP • Avoids ugly HTML embedded in Java code • Helps to separate presentation from implementation logic • Causes a servlet class to be generated and compiled automatically
A Simple JSP Example <html> <body> The page count is: <% out.println(Counter.getCount()); %> </body> </html> package foo; publicclassCounter { privatestaticintcount; publicstaticsynchronizedintgetCount() { count++; returncount; } }
A Simple JSP Example <html> <body> The page count is: <% out.println(Counter.getCount()); %> </body> </html> package foo; publicclassCounter { privatestaticintcount; publicstaticsynchronizedintgetCount() { count++; returncount; } } This causes an error! Why?
A Simple JSP Example <!-- We need to import the package Counter lives in... --> <%@ page import="foo.*" %> <html> <body> The page count is: <% <!-- ...or use a fully scoped name --> out.println(foo.Counter.getCount()); %> </body> </html>
A Simple JSP Example <!-- We need to import the package Counter lives in... --> <%@ page import="foo.*" %> <html> <body> The page count is: <% <!-- ...or use a fully scoped name --> out.println(foo.Counter.getCount()); %> </body> </html> But wait! I thought we were trying to eliminate all of the calls to println?
A Simple JSP Example <%@ page import="foo.*" %> <html> <body> The page count is: <%= Counter.getCount() %> <!-- Notice there's no ; up there --> </body> </html>
JSP Expressions • Which of these are valid? <%= 27 %> <%= ((Math.random() + 5) * 2); %> <%= “27” %> <%= Math.random() %> <%= String s = “foo” %> <%= new String[3] %> <% = 42 * 20 %> <%= 5 > 3 %> <%= false %> <%= new Counter() %>
JSP Expressions • Which of these are valid? <%= 27 %> <%= ((Math.random() + 5) * 2); %> Can’t have semicolon <%= “27” %> <%= Math.random() %> <%= String s = “foo” %> Can’t have variable declaration <%= new String[3] %> <% = 42 * 20 %> Can’t have space between the % and the = <%= 5 > 3 %> <%= false %> <%= new Counter() %>
A Simple JSP Example <%@ page import="foo.*" %> <html> <body> The page count is: <%= Counter.getCount() %> <!-- Notice there's no ; up there --> </body> </html> If this is creating a Java class, can't we get rid of Counter?
A Simple JSP Example <html> <body> <%intcount = 0; %> The page count is: <%= ++count %> </body> </html> Will this work? What code will be generated?
A Simple JSP Example <html> <body> <%intcount = 0; %> The page count is: <%= ++count %> </body> </html> publicvoid_jspService(HttpServletRequest request, HttpServletResponse response) throwsIOException, ServletException { PrintWriter out = response.getWriter(); response.setContentType("text/html"); out.write("<html><body>"); intcount = 0; out.write("The page count is now:"); out.print(++count); out.write("</body></html>"); }
A Simple JSP Example <html> <body> <%!intcount = 0; %> The page count is: <%= ++count %> </body> </html>
A Simple JSP Example <html> <body> <%!intcount = 0; %> The page count is: <%= ++count %> </body> </html> intcount = 0; publicvoid_jspService(HttpServletRequest request, HttpServletResponse response) throwsIOException, ServletException { PrintWriter out = response.getWriter(); response.setContentType("text/html"); out.write("<html><body>"); out.write("The page count is now:"); out.print(++count); out.write("</body></html>"); }
Implicit Objects • JspWriter out • HttpServletRequest request • HttpServletResponse response • HttpSession session • ServletContext application • ServletConfig config • Throwable exception • PageContext page context • Object page
Be the Container <!-- What output is produced? --> <html><body> Test scriptlets... <%inty = 5 + x; %> <%intx = 2; %> </body></html>
Be the Container <!-- What output is produced? --> <html><body> Test scriptlets... <%inty = 5 + x; %> <%intx = 2; %> </body></html> Compile Error!
Be the Container <!-- What output is produced? --> <%@ page import="java.util.*" %> <html><body> Test scriptlets... <% ArrayList list = newArrayList(); list.add("foo"); %> <%= list.get(0) %> </body></html>
Be the Container <!-- What output is produced? --> <%@ page import="java.util.*" %> <html><body> Test scriptlets... <% ArrayList list = newArrayList(); list.add("foo"); %> <%= list.get(0) %> </body></html> Test scriptlets... foo
Be the Container <!-- What output is produced? --> <html><body> Test scriptlets... <%!intx = 42; %> <%intx = 22; %> <%= x %> </body></html>
Be the Container <!-- What output is produced? --> <html><body> Test scriptlets... <%!intx = 42; %> <%intx = 22; %> <%= x %> </body></html> Test scriptlets... 22
JSP Comments <!-- HTML comment --> This is included in the HTML sent to the browser, and then ignored. <%-- JSP comment --%> This is ignored by the compiler, and never makes it into the servlet class.
Generated Servlet API • jspInit() – called from the servlet's init() method. Can be overridden. • jspDestroy() – called from the servlet's destroy() method. Can be overridden. • _jspService() – called from the servlet's service() method. Can't be overridden.
JSP Lifecycle • JSP is deployed in a web app • Container reads DD, but doesn’t do anything yet • Client requests JSP • Container translates JSP to a servlet, compiles it, and loads the servlet • Servlet instance is created, and jspInit() is executed • Container creates thread to handle request, and calls _jspService() method. • The rest of the request is handled like an ordinary servlet request
JSP Attributes • Application application.setAttribute("foo", barObj); • Request request.setAttribute("foo", barObj); • Session session.setAttribute("foo", barObj); • Page pageContext.setAttribute("foo", barObj);
JSP Attributes <!-- PageContext can be used to get/set attributes for all scopes --> <!-- Get page-scoped attribute --> <%= pageContext.getAttribute("foo") %> <!-- Get request-scoped attribute --> <%= pageContext.getAttribute("foo", PageContext.REQUEST_SCOPE) %> <!-- Get session-scoped attribute --> <%= pageContext.getAttribute("foo", PageContext.SESSION_SCOPE) %> <!-- Get an application-scoped attribute --> <%= pageContext.getAttribute("foo", PageContext.APPLICATION_SCOPE) %> <!-- Find an attribute in most-specific scope --> <%= pageContext.findAttribute("foo") %>
Eliminating Java in JSPs • This is the ultimate goal – presentation and implementation should be completely separate • Allows designers to edit JSPs without fear of breaking things, and vice versa
EL Sneak Preview <!-- Instead of... --> Please contact: <%= application.getAttribute("mail") %> <!-- ...we use --> Please contact: ${applicationScope.mail} <!– We can disable scripting elements in the DD: --> <web-app ...> ... <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <scripting-invalid>true</scripting-invalid> </jsp-property-group> </jsp-config> ... </web-app>
Progress Check • Due next week: • Lab 8-1 Servlets