Remapping Path Names with Servlets
Mark is the author of Special Edition Using Java Server Pages and Servlets (2000, Que).
Java Server Pages and servlets enable you to associate data with a browser using a mechanism called sessions. The servlet container generates a random session ID and stores it on the browser in the form of a cookie. Occasionally, the session mechanism isn't good enough. When you open multiple windows from the same browser, the windows all share the same cookie. Because these windows share the same cookie, they all have the same session on the server.
Most of the time, you don't care whether all the windows share the same cookie. After all, you usually use sessions to keep track of a particular user, and it's reasonable to assume that the same person is using the various browser windows.
If your application must keep track of individual browser windows, you have quite a challenge. Fortunately, you can store a virtual session ID in the URL. One of the interesting aspects of servlets is that a servlet can access the entire path used to run the servlet. You can create servlets to perform interesting kinds of path mapping. For example, you can create a virtual filesystem or a proxy that maps a path on one server to a URL on another.
To keep track of multiple browser windows, use the following servlet to pull the virtual session ID from the path before forwarding to a page:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class PathServlet extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String extraInfo = request.getPathInfo(); // Locate the next slash in the path (assume there is one at position 0) int slashPos = extraInfo.indexOf('/', 1); if (slashPos > 0) { // Get the subsession id and the real path to access String virtSession = extraInfo.substring(1, slashPos); String fullPath = extraInfo.substring(slashPos); // Store the subsession where a JSP can get it request.setAttribute("subsessionId", virtSession); // Assume that the real path is under /appsubdir getServletContext().getRequestDispatcher("/appsubdir"+fullPath). forward(request, response); } } }
The idea behind this servlet is simple. It takes the portion of the path following the servlet's path and then extracts the virtual session ID from the path. It then forwards the request onto a page located in the /appsubdir directory.
The servlet doesn't generate the virtual session ID at first, however. You must create a JSP or a servlet to generate the ID the first time. You can use the following JSP to create the virtual session:
<%@ page import="java.util.*"%> <% Random r = new Random(); String virtSession = ""+r.nextLong(); Hashtable table = new Hashtable(); session.setAttribute(virtSession, table); table.put("random1", ""+r.nextLong()); table.put("random2", ""+r.nextLong()); table.put("random3", ""+r.nextLong()); response.sendRedirect("/servlet/PathServlet/"+virtSession+ "/ShowSessionInfo.jsp"); %>
This JSP creates a hash table for storing virtual session data and then stores the hash table in the session object using a random virtual session ID. Finally, it sends the browser to another page via the path servlet.
The PathServlet class stores the virtual session ID in the current request so that you can access it easily. The following JSP fetches the virtual session ID and then retrieves the random values stored in the virtual session hash table:
<%@ page import="java.util.*" %> <html> <body> SessionID = <%= session.getId() %><p> <% String virtSession = (String) request.getAttribute("subsessionId"); Hashtable subsessionParams = (Hashtable) session.getAttribute(virtSession); %> Random1 = <%= subsessionParams.get("random1")%><p> Random2 = <%= subsessionParams.get("random2")%><p> Random3 = <%= subsessionParams.get("random3")%><p> </body> </html>
You can also create servlets that act like proxies to access other sites. For example, you can extract the path at the end of the servlet path and use it to access another site. For example, given a URL of /servlet/SomeServlet/www.cnn.com/, you can extract the remaining part, /www.cnn.com/, and access it using the URL class. This gives you what amounts to a proxy service. The following class functions like a remote proxy most of the time. If you access a page that contains absolute URLs, the absolute URLs knock the /servlet/RemotePathServlet out of the path so that the proxy doesn't work.
import java.io.*; import java.net.*; import javax.servlet.*; import javax.servlet.http.*; public class RemotePathServlet extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String extraInfo = request.getPathInfo(); try { // Remap request for this servlet to www.wutka.com URL url = new URL("http:/"+extraInfo); // Open a connection to the alternate site URLConnection urlConn = url.openConnection(); // Copy the content type response.setContentType(urlConn.getContentType()); // If the URL specifies a content length, copy it if (urlConn.getContentLength() > 0) { response.setContentLength(urlConn.getContentLength()); } InputStream in = urlConn.getInputStream(); OutputStream out = response.getOutputStream(); byte[] buffer = new byte[4096]; int len; // Copy the data from the connection to the servlet output stream while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } } catch (Exception exc) { throw new IOException(exc.toString()); } } }
About the Author
Mark Wutka is the president of Wutka Consulting and specializes in helping companies get the most out of Java. He has built numerous Java, JSP, and servlet applications, including several online ordering applications. In a past life, he was the chief architect on a large, object-oriented distributed system providing automation for the flight operations division of a major airline; for nine years he designed and implemented numerous systems in Java, C, C++, and Smalltalk for that same airline. Mark previously contributed chapters to Special Edition Using Java 2 Platform and is the author of Special Edition Using Java Server Pages and Servlets and Hacking Java. His next book, Special Edition Using Java 2 Enterprise Edition, will be available in April.