001: /*
002: * Created on Aug 5, 2005
003: */
004: package uk.org.ponder.rsf.processor;
005:
006: import java.net.MalformedURLException;
007:
008: import uk.org.ponder.errorutil.ConfigurationException;
009: import uk.org.ponder.errorutil.CoreMessages;
010: import uk.org.ponder.messageutil.TargettedMessage;
011: import uk.org.ponder.rsf.flow.errors.SilentRedirectException;
012: import uk.org.ponder.rsf.flow.errors.ViewExceptionStrategy;
013: import uk.org.ponder.rsf.state.ErrorStateManager;
014: import uk.org.ponder.rsf.viewstate.AnyViewParameters;
015: import uk.org.ponder.rsf.viewstate.ErrorViewParameters;
016: import uk.org.ponder.rsf.viewstate.RedirectViewParameters;
017: import uk.org.ponder.rsf.viewstate.ViewParameters;
018: import uk.org.ponder.streamutil.write.PrintOutputStream;
019: import uk.org.ponder.util.Logger;
020: import uk.org.ponder.util.UniversalRuntimeException;
021:
022: /**
023: * This request-scope bean exists to bracket the creation and operation of the
024: * rendering process, such that any "first" exception causes a redirect to a
025: * default view. A "double fault", caught above in the RootHandlerBean, will
026: * render a fatal error message in the raw.
027: *
028: * @author Antranig Basman (antranig@caret.cam.ac.uk)
029: *
030: */
031: public class RenderHandlerBracketer {
032: private ViewExceptionStrategy ves;
033: private ErrorStateManager errorstatemanager;
034: private AnyViewParameters anyviewparams;
035: private RenderHandler renderhandler;
036: private boolean redirectlevel1 = true;
037:
038: public void setViewExceptionStrategy(ViewExceptionStrategy ves) {
039: this .ves = ves;
040: }
041:
042: public void setRedirectOnLevel1Error(boolean redirectlevel1) {
043: this .redirectlevel1 = redirectlevel1;
044: }
045:
046: public void setErrorStateManager(ErrorStateManager errorstatemanager) {
047: this .errorstatemanager = errorstatemanager;
048: }
049:
050: public void setViewParameters(AnyViewParameters viewparams) {
051: this .anyviewparams = viewparams;
052: }
053:
054: // This is a lazy dependency
055: public void setRenderHandler(RenderHandler renderhandler) {
056: this .renderhandler = renderhandler;
057: }
058:
059: /**
060: * The beanlocator is passed in to allow the late location of the
061: * GetHandlerImpl bean which needs to occur in a controlled exception context.
062: */
063: public AnyViewParameters handle(PrintOutputStream pos) {
064: AnyViewParameters incoming = null;
065: boolean iserrorredirect = false;
066: try {
067: incoming = anyviewparams.get();
068: // An AnyViewParameters is CERTAINLY a redirect, issued by an interceptor
069: if (!(anyviewparams instanceof ViewParameters)) {
070: return anyviewparams;
071: }
072: if (anyviewparams instanceof RedirectViewParameters) {
073: return ((RedirectViewParameters) anyviewparams).target;
074: }
075: ViewParameters viewparams = (ViewParameters) incoming;
076: iserrorredirect = viewparams.errorredirect != null;
077: // YES, reach into the original request! somewhat bad...
078: viewparams.errorredirect = null;
079:
080: if (viewparams instanceof ErrorViewParameters) {
081: throw UniversalRuntimeException.accumulate(
082: new MalformedURLException(),
083: "Request for bad view with ID "
084: + viewparams.viewID + " ");
085: }
086: renderhandler.handle(pos);
087: } catch (Exception e) {
088:
089: // if a request comes in for an invalid view, redirect it onto a default
090: AnyViewParameters redirect = handleLevel1Error(
091: (ViewParameters) incoming, e, iserrorredirect);
092: return redirect;
093: } finally {
094: errorstatemanager.requestComplete();
095: }
096: // if an exception escapes this block, handler will externally call
097: // renderFatalError
098: return null;
099: }
100:
101: // a "Level 1" GET error simply attempts to redirect onto a default
102: // view, with errors intact.
103: public AnyViewParameters handleLevel1Error(
104: ViewParameters viewparams, Exception e,
105: boolean iserrorredirect) {
106: UniversalRuntimeException invest = UniversalRuntimeException
107: .accumulate(e);
108: Throwable target = invest.getTargetException();
109: boolean issilent = target != null
110: && target instanceof SilentRedirectException;
111: if (!issilent) {
112: Logger.log.warn("Exception rendering view: ", e);
113: }
114:
115: if (target != null) {
116: Logger.log.warn("Got target exception of "
117: + target.getClass());
118: }
119:
120: if (target instanceof ConfigurationException
121: || target instanceof Error || iserrorredirect
122: || !redirectlevel1) {
123: throw invest;
124: }
125: AnyViewParameters outgoingo = null;
126: if (issilent) {
127: SilentRedirectException silent = (SilentRedirectException) target;
128: outgoingo = silent.redirectTo;
129: }
130: if (outgoingo == null) {
131: outgoingo = ves.handleException(e, viewparams);
132: }
133:
134: // make sure this method is prodded FIRST, because requestComplete
135: // (which would ordinarily allocate the token on seeing an error state) is
136: // only called AFTER we visibly return from handle() above.
137: if (!issilent && outgoingo instanceof ViewParameters) {
138: ViewParameters outgoing = (ViewParameters) outgoingo;
139: String tokenid = errorstatemanager.allocateOutgoingToken();
140: outgoing.errortoken = tokenid;
141: outgoing.errorredirect = "1";
142: Logger.log.warn("Error creating view tree - token "
143: + tokenid);
144: TargettedMessage newerror = new TargettedMessage(
145: CoreMessages.GENERAL_SHOW_ERROR,
146: new Object[] { tokenid });
147: errorstatemanager.getTargettedMessageList().addMessage(
148: newerror);
149: }
150:
151: return outgoingo;
152: }
153:
154: }
|