--- /dev/null
+// ServletWrapperFrame.java\r
+// $Id: ServletWrapperFrame.java,v 1.1 2010/06/15 12:24:09 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.servlet;\r
+\r
+import javax.servlet.ServletException;\r
+import javax.servlet.UnavailableException;\r
+\r
+import java.io.IOException;\r
+import java.io.PipedInputStream;\r
+import java.io.PipedOutputStream;\r
+\r
+import org.w3c.www.mime.MimeType;\r
+\r
+import org.w3c.www.http.HTTP;\r
+import org.w3c.www.http.HttpEntityMessage;\r
+import org.w3c.www.http.HttpMessage;\r
+import org.w3c.www.http.HttpReplyMessage;\r
+\r
+import org.w3c.jigsaw.http.httpd;\r
+import org.w3c.jigsaw.http.HTTPException;\r
+import org.w3c.jigsaw.http.Reply;\r
+import org.w3c.jigsaw.http.Request;\r
+\r
+import org.w3c.jigsaw.frames.HTTPFrame;\r
+\r
+import org.w3c.tools.resources.FramedResource;\r
+import org.w3c.tools.resources.LookupResult;\r
+import org.w3c.tools.resources.LookupState;\r
+import org.w3c.tools.resources.ProtocolException;\r
+import org.w3c.tools.resources.ReplyInterface;\r
+import org.w3c.tools.resources.RequestInterface;\r
+import org.w3c.tools.resources.Resource;\r
+import org.w3c.tools.resources.ResourceException;\r
+import org.w3c.tools.resources.ResourceFrame;\r
+import org.w3c.tools.resources.ServerInterface;\r
+\r
+import org.w3c.tools.resources.ProtocolException;\r
+import org.w3c.tools.resources.ResourceException;\r
+\r
+/**\r
+ * @author Alexandre Rafalovitch <alex@access.com.au>\r
+ * @author Anselm Baird-Smith <abaird@w3.org>\r
+ * @author Benoit Mahe <bmahe@w3.org>\r
+ */\r
+\r
+public class ServletWrapperFrame extends HTTPFrame {\r
+\r
+ protected ServletWrapper wrapper = null;\r
+\r
+ /**\r
+ * Register our resource. Must be an instance of ServletWrapper.\r
+ */\r
+ public void registerResource(FramedResource resource) {\r
+ super.registerOtherResource(resource);\r
+ if (resource instanceof ServletWrapper)\r
+ wrapper = (ServletWrapper) resource;\r
+ }\r
+\r
+ /**\r
+ * Create a reply to answer to request on this file.\r
+ * This method will create a suitable reply (matching the given request)\r
+ * and will set all its default header values to the appropriate \r
+ * values. The reply will not have LastModified field setted.\r
+ * @param request The request to make a reply for.\r
+ * @return An instance of Reply, suited to answer this request.\r
+ */\r
+\r
+ public Reply createDefaultReply(Request request, int status) {\r
+ Reply reply = super.createDefaultReply(request, status);\r
+ reply.setLastModified( -1 );\r
+ return reply;\r
+ }\r
+\r
+ /**\r
+ * Dispatch the give request to our servlet.\r
+ * <p>If the servlet cannot be inititalized, we just throw an error message\r
+ * otherwise, we just delegate that request processing to the underlying \r
+ * servlet instance.\r
+ * @param request The request to be processed.\r
+ * @exception ProtocolException If the wrapped servlet is not initialized.\r
+ * @exception ResourceException If the resource got a fatal error.\r
+ */\r
+\r
+ public ReplyInterface perform(RequestInterface req)\r
+ throws ProtocolException, ResourceException\r
+ {\r
+ ReplyInterface repi = performFrames(req);\r
+ if (repi != null)\r
+ return repi;\r
+\r
+ if (! checkRequest(req))\r
+ return null;\r
+\r
+ Request request = (Request) req;\r
+ PipedInputStream pis = null;\r
+\r
+ if (wrapper == null) {\r
+ Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+ reply.setContent("Servlet Wrapper Frame not configured properly: "+\r
+ "must be attached to a ServletWrapper.");\r
+ throw new HTTPException(reply);\r
+ }\r
+\r
+ try {\r
+ wrapper.checkServlet();\r
+ } catch (ClassNotFoundException ex) {\r
+ Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+ reply.setContent("The server was unable to find the "+\r
+ "servlet class : "+ex.getMessage());\r
+ if ( wrapper.debug )\r
+ ex.printStackTrace();\r
+ throw new HTTPException(reply);\r
+ } catch (ServletException ex) {\r
+ Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+ reply.setContent("The server was unable to initialize the "+\r
+ "servlet : "+ex.getMessage());\r
+ if ( wrapper.debug )\r
+ ex.printStackTrace();\r
+ throw new HTTPException(reply);\r
+ }\r
+\r
+ // Check that the servlet has been initialized properly:\r
+ if ( ! wrapper.isInited() ) {\r
+ Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+ reply.setContent("Servlet not configured properly");\r
+ throw new HTTPException(reply);\r
+ } \r
+ // Dispatch the request:\r
+ Reply reply = createDefaultReply(request, HTTP.OK);\r
+ reply.setContentType(MimeType.TEXT_HTML);\r
+ try {\r
+ if (request.hasState(JigsawHttpServletResponse.INCLUDED)) {\r
+ wrapper.service(request, reply);\r
+ } else {\r
+ pis = new PipedInputStream();\r
+ request.setState(JigsawHttpServletResponse.STREAM, pis);\r
+ PipedOutputStream pos = new PipedOutputStream(pis);\r
+ reply.setState(JigsawHttpServletResponse.STREAM, pos);\r
+ reply.setStream(pis);\r
+ Object o = new Object();\r
+ reply.setState(JigsawHttpServletResponse.MONITOR, o);\r
+ // wait until the reply is constructed by the processing thread\r
+ ServerInterface server = getServer();\r
+ if (server instanceof httpd) {\r
+ synchronized (o) {\r
+ wrapper.service(request, reply);\r
+ o.wait((long)((httpd)server).getRequestTimeOut());\r
+ }\r
+ Object strm;\r
+ strm = reply.getState(JigsawHttpServletResponse.STREAM);\r
+ if (strm != null) {\r
+ // it is a timeout\r
+ try {\r
+ pis.close();\r
+ pos.close();\r
+ } catch (IOException ex) {};\r
+ if (strm instanceof PipedOutputStream) {\r
+ ServletWrapper.ServletRunner r;\r
+ r = (ServletWrapper.ServletRunner) \r
+ reply.getState(ServletWrapper.RUNNER);\r
+ if (r != null) {\r
+ r.signalTimeout();\r
+ }\r
+ throw new ServletException("Timed out");\r
+ }\r
+ }\r
+ } else {\r
+ synchronized (o) {\r
+ wrapper.service(request, reply);\r
+ o.wait();\r
+ }\r
+ }\r
+ }\r
+ } catch (UnavailableException uex) {\r
+ reply = request.makeReply(HTTP.SERVICE_UNAVAILABLE);\r
+ if (uex.isPermanent()) {\r
+ reply.setContent("<h2>The servlet is permanently "+\r
+ "unavailable :</h2>"+\r
+ "Details: <b>"+uex.getMessage()+"</b>");\r
+ } else {\r
+ int delay = uex.getUnavailableSeconds();\r
+ if (delay > 0) {\r
+ reply.setRetryAfter(delay);\r
+ reply.setContent("<h2>The servlet is temporarily "+\r
+ "unavailable :</h2>"+\r
+ "Delay : "+delay+\r
+ " seconds<br><br>Details: <b>"+\r
+ uex.getMessage()+"</b>");\r
+ } else {\r
+ reply.setContent("<h2>The servlet is temporarily "+\r
+ "unavailable :</h2>"+\r
+ "Details: <b>"+uex.getMessage()+"</b>");\r
+ }\r
+ }\r
+ if (pis != null) {\r
+ try {\r
+ pis.close();\r
+ } catch (IOException ioex) {}\r
+ }\r
+ } catch (Exception ex) {\r
+ if ( wrapper.debug )\r
+ ex.printStackTrace();\r
+ reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+ reply.setContent("Servlet has thrown exception:" + ex.toString());\r
+ if (pis != null) {\r
+ try {\r
+ pis.close();\r
+ } catch (IOException ioex) {}\r
+ }\r
+ }\r
+ if (reply != null) {\r
+ reply.setDynamic(true);\r
+ }\r
+ return reply;\r
+ }\r
+\r
+ /**\r
+ * Jigsaw's lookup on servlets.\r
+ * Once here, we have reached a leaf servlet (or at least the remaining\r
+ * lookup is to be done at the servlet itself). We keep track of the\r
+ * <em>path info</em> and mark that servlet as the target of request.\r
+ * @param ls The lookup state.\r
+ * @param lr The lookup result.\r
+ * @exception ProtocolException If some error occurs.\r
+ */\r
+\r
+ protected boolean lookupOther(LookupState ls, LookupResult lr)\r
+ throws ProtocolException\r
+ {\r
+ // Get the extra path information:\r
+ String extraPath = ls.getRemainingPath(true);\r
+ if ((extraPath == null) || extraPath.equals(""))\r
+ extraPath = "/";\r
+ // Keep this path info into the request, if possible:\r
+ Request request = (Request) ls.getRequest();\r
+ if ( request != null ) {\r
+ if (request.getState(JigsawRequestDispatcher.PATH_INFO_P) == null)\r
+ request.setState(JigsawRequestDispatcher.PATH_INFO_P, \r
+ extraPath);\r
+ }\r
+ lr.setTarget(resource.getResourceReference());\r
+ return super.lookupOther(ls, lr);\r
+ }\r
+\r
+}\r