001: /*
002: * Created on Aug 5, 2005
003: */
004: package uk.org.ponder.rsf.servlet;
005:
006: import java.io.IOException;
007: import java.io.OutputStream;
008:
009: import javax.servlet.http.HttpServletRequest;
010: import javax.servlet.http.HttpServletResponse;
011:
012: import uk.org.ponder.rsf.components.ParameterList;
013: import uk.org.ponder.rsf.content.ContentTypeInfo;
014: import uk.org.ponder.rsf.processor.ActionHandler;
015: import uk.org.ponder.rsf.processor.DefaultFatalErrorHandler;
016: import uk.org.ponder.rsf.processor.FatalErrorHandler;
017: import uk.org.ponder.rsf.processor.HandlerHook;
018: import uk.org.ponder.rsf.processor.RenderHandlerBracketer;
019: import uk.org.ponder.rsf.renderer.RenderUtil;
020: import uk.org.ponder.rsf.request.EarlyRequestParser;
021: import uk.org.ponder.rsf.request.LazarusRedirector;
022: import uk.org.ponder.rsf.viewstate.AnyViewParameters;
023: import uk.org.ponder.rsf.viewstate.NoViewParameters;
024: import uk.org.ponder.rsf.viewstate.RawViewParameters;
025: import uk.org.ponder.rsf.viewstate.ViewParameters;
026: import uk.org.ponder.rsf.viewstate.ViewStateHandler;
027: import uk.org.ponder.servletutil.ServletResponseWriter;
028: import uk.org.ponder.streamutil.write.OutputStreamPOS;
029: import uk.org.ponder.streamutil.write.PrintOutputStream;
030: import uk.org.ponder.util.Logger;
031: import uk.org.ponder.util.UniversalRuntimeException;
032:
033: /**
034: * The RootHandlerBean is the main entry point for handling of the
035: * HttpServletRequest cycle. Virtually all servlet-dependent logic is placed in
036: * this class, including initiating parameter decoding (eventually done by
037: * RSAC), setting up the response writer and issuing client redirects. From
038: * here, handling forks to the GetHandler and PostHandler in the
039: * <code>processor</code> package.
040: *
041: * @author Antranig Basman (antranig@caret.cam.ac.uk)
042: *
043: */
044: public class RootHandlerBean implements HandlerHook {
045: private String requesttype;
046: private HttpServletRequest request;
047: private HttpServletResponse response;
048: private ViewStateHandler viewstatehandler;
049: private ParameterList outgoingparams;
050: private RenderHandlerBracketer renderhandlerbracketer;
051: private ActionHandler actionhandler;
052: private HandlerHook handlerhook;
053: private ContentTypeInfo contenttypeinfo;
054: private FatalErrorHandler fatalErrorHandler;
055: private LazarusRedirector lazarusRedirector;
056:
057: public void setHttpServletRequest(HttpServletRequest request) {
058: this .request = request;
059: }
060:
061: public void setHttpServletResponse(HttpServletResponse response) {
062: this .response = response;
063: }
064:
065: public void setRequestType(String requesttype) {
066: this .requesttype = requesttype;
067: }
068:
069: public void setViewStateHandler(ViewStateHandler viewstatehandler) {
070: this .viewstatehandler = viewstatehandler;
071: }
072:
073: public void setOutgoingParams(ParameterList outgoingparams) {
074: this .outgoingparams = outgoingparams;
075: }
076:
077: public void setRenderHandlerBracketer(
078: RenderHandlerBracketer renderhandlerbracketer) {
079: this .renderhandlerbracketer = renderhandlerbracketer;
080: }
081:
082: public void setActionHandler(ActionHandler actionhandler) {
083: this .actionhandler = actionhandler;
084: }
085:
086: public void setFatalErrorHandler(FatalErrorHandler fatalErrorHandler) {
087: this .fatalErrorHandler = fatalErrorHandler;
088: }
089:
090: public void setContentTypeInfo(ContentTypeInfo contenttypeinfo) {
091: this .contenttypeinfo = contenttypeinfo;
092: }
093:
094: public void setLazarusRedirector(LazarusRedirector lazarusRedirector) {
095: this .lazarusRedirector = lazarusRedirector;
096: }
097:
098: public boolean handle() {
099: if (handlerhook == null || !handlerhook.handle()) {
100: if (requesttype.equals(EarlyRequestParser.RENDER_REQUEST)) {
101: handleGet();
102: } else {
103: handlePost();
104: }
105: }
106: Logger.log.info("Request handled");
107: return true;
108: }
109:
110: public void setHandlerHook(HandlerHook handlerhook) {
111: this .handlerhook = handlerhook;
112: }
113:
114: private void handleGet() {
115: PrintOutputStream pos = setupResponseWriter(
116: contenttypeinfo.contentTypeHeader, request, response);
117: String fatalcode = null;
118: Throwable t1 = null;
119: try {
120: AnyViewParameters redirect = renderhandlerbracketer
121: .handle(pos);
122:
123: if (redirect != null) {
124: issueRedirect(redirect, response);
125: }
126: } catch (Throwable t) {
127: fatalcode = DefaultFatalErrorHandler
128: .handleFatalErrorStrategy(fatalErrorHandler, t, pos);
129: t1 = t;
130: } finally {
131: if (fatalcode != FatalErrorHandler.HANDLE_EXCEPTION_UPSTAIRS) {
132: // leave the stream open for a handler outside the system
133: pos.close();
134: } else {
135: throw UniversalRuntimeException.accumulate(t1);
136: }
137: }
138: }
139:
140: private void handlePost() {
141:
142: AnyViewParameters redirect = actionhandler.handle();
143:
144: issueRedirect(redirect, response);
145: }
146:
147: // If this is a web service request, send the required redirect URL
148: // to the client via the body of the POST response. Otherwise, issue
149: // the redirect directly to the client via this connection.
150: // TODO: This method might need some state, depending on the client.
151: // maybe we can do this all with "request beans"?
152: public void issueRedirect(AnyViewParameters viewparamso,
153: HttpServletResponse response) {
154: if (viewparamso instanceof NoViewParameters)
155: return;
156:
157: String path = viewparamso instanceof RawViewParameters ? ((RawViewParameters) viewparamso).URL
158: : viewstatehandler
159: .getFullURL((ViewParameters) viewparamso);
160: path = RenderUtil.appendAttributes(path, RenderUtil
161: .makeURLAttributes(outgoingparams));
162: // TODO: This is a hack, pending a bit more thought.
163:
164: Logger.log.info("Redirecting to " + path);
165: try {
166: if (contenttypeinfo.directRedirects
167: && viewparamso instanceof ViewParameters) {
168: ViewParameters viewparams = (ViewParameters) viewparamso;
169: lazarusRedirector.lazarusRedirect(viewparams);
170: } else {
171: response.sendRedirect(path);
172: }
173: } catch (IOException ioe) {
174: Logger.log.warn("Error redirecting to URL " + path, ioe);
175: }
176: }
177:
178: public static PrintOutputStream setupResponseWriter(
179: String contenttype, HttpServletRequest request,
180: HttpServletResponse response) {
181: try {
182: response.setContentType(contenttype);
183: // response.setContentType("application/xhtml+xml; charset=UTF-8");
184:
185: ServletResponseWriter srw = new ServletResponseWriter(
186: response);
187: OutputStream os = srw.getOutputStream();
188: PrintOutputStream pos = new OutputStreamPOS(os, "UTF-8");
189:
190: String acceptHeader = request.getHeader("Accept");
191:
192: // Work-around for JSF 1.0 RI bug: failing to accept "*/*" and
193: // and "text/*" as valid replacements for "text/html"
194: if (acceptHeader != null
195: && (acceptHeader.indexOf("*/*") != -1 || acceptHeader
196: .indexOf("text/*") != -1)) {
197: acceptHeader += ",text/html";
198: }
199:
200: String responseencoding = response.getCharacterEncoding();
201: response.setHeader("Accept", acceptHeader);
202: return pos;
203: } catch (Exception ioe) {
204: throw UniversalRuntimeException.accumulate(ioe,
205: "Error setting up response writer");
206: }
207: }
208:
209: }
|