001: /*
002: * Component.java February 2001
003: *
004: * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General
016: * Public License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018: * Boston, MA 02111-1307 USA
019: */
020:
021: package simple.http.serve;
022:
023: import java.io.FileNotFoundException;
024: import java.io.IOException;
025: import simple.http.Response;
026: import simple.http.Request;
027:
028: /**
029: * This is an abstract <code>Resource</code> that handles the basic
030: * HTTP status reports. For example messages like '404 Not Found'
031: * are represented using this abstraction. This <code>Resource</code>
032: * can be subclassed to give a <code>Resource</code> the ability to
033: * handle all generic status reports for 3xx, 4xx and 5xx defined by
034: * RFC 2616.
035: * <p>
036: * This uses a various <code>Report</code> objects to generate error
037: * and status messages using the <code>Format</code> supplied. This
038: * also enables exceptions that propagate from the service objects
039: * to be classified and for descriptions of those exceptions to be
040: * represented as <code>Report</code> objects that can be be used to
041: * generate a formatted message that can be presented to the client.
042: *
043: * @author Niall Gallagher
044: */
045: public abstract class Component implements Resource {
046:
047: /**
048: * The <code>Context</code> that this resource is in.
049: */
050: protected Context context;
051:
052: /**
053: * Constructor that creates a <code>Component</code> without
054: * any <code>Context</code> object. This is used so that if the
055: * resource is a <code>ProtocolHandler</code> or some other form
056: * of resource that does not require a context then this will
057: * allow that resource to inherit the functionality of this. The
058: * typical implementation however will not use this constructor.
059: * If this is used and a context is not set then there will be
060: * an exception in <code>handle(Request,Response,int)</code>.
061: */
062: protected Component() {
063: super ();
064: }
065:
066: /**
067: * Constructor for the <code>Component</code> is given the
068: * <code>Context</code> so that it can generate status reports.
069: * Every implementation of the <code>Component</code> needs
070: * to be constructed with a <code>Context</code> to ensure that
071: * the generation of error and status messages is successful.
072: *
073: * @param context the context that this resource is in
074: */
075: protected Component(Context context) {
076: this .context = context;
077: }
078:
079: /**
080: * This <code>handle</code> is provided so that if any errors
081: * occur when processing a HTTP transaction a '500 Server Error'
082: * message will be sent to the client. This is used to invoke
083: * the <code>process</code> method which subclasses should
084: * implement to process the HTTP transaction. If the exception
085: * is a <code>SecurityException</code> '403 Forbidden' is used
086: * and a <code>FileNotFoundException</code> is '404 Not Found'.
087: * <p>
088: * Any <code>Exception</code> thrown from the <code>process</code>
089: * method will be captured and the <code>Request</code> and
090: * <code>Response</code> are handled by the default error handler
091: * method <code>handle(Request,Response,int)</code> with the code
092: * 500 which indicates the HTTP/1.1 error message 'Server Error'
093: * <p>
094: * This does not throw ant <code>Exception</code> however any
095: * user should handle <code>RuntimeException</code>'s that may
096: * be thrown from <code>handle(Request,Response,int)</code>.
097: *
098: * @param req the <code>Request</code> object to be processed
099: * @param resp the <code>Response</code> object to be processed
100: */
101: public void handle(Request req, Response resp) {
102: try {
103: process(req, resp);
104: } catch (SecurityException cause) {
105: handle(req, resp, new ErrorReport(cause, 403));
106: } catch (FileNotFoundException cause) {
107: handle(req, resp, new ErrorReport(cause, 404));
108: } catch (Throwable cause) {
109: handle(req, resp, new ErrorReport(cause, 500));
110: }
111: }
112:
113: /**
114: * This is used to generate the status report from a status code.
115: * The set of status reports that can have a valid response are the
116: * messages that are defined in RFC 2616. If the status code given
117: * does not have a valid entry then this will result in an status
118: * message description of 'Unknown'.
119: * <p>
120: * This does not throw <code>Exception</code>'s but users should
121: * be prepared to handle any <code>RuntimeException</code>'s that
122: * could propagate from this. If the <code>Response</code> has
123: * been committed then this will return quietly. Typically there
124: * will be an <code>IOException</code> writing the content body if
125: * the stream has been closed. This will not report such exceptions.
126: *
127: * @param req the <code>Request</code> object to be processed
128: * @param resp the <code>Response</code> object to be processed
129: * @param code this is the HTTP status code of the response
130: */
131: public void handle(Request req, Response resp, int code) {
132: handle(req, resp, new StatusReport(code));
133: }
134:
135: /**
136: * This is used to generate a formatted message using a report to
137: * describe the change in status. This uses the <code>Format</code>
138: * object to prepare a formatted message that can be presented to
139: * the client. This message will describe the status using the
140: * issued <code>Report</code> obejct. If the status code given
141: * does not have a valid entry then this will result in an status
142: * message description of 'Unknown'.
143: * <p>
144: * This does not throw <code>Exception</code>'s but users should
145: * be prepared to handle any <code>RuntimeException</code>'s that
146: * could propagate from this. If the <code>Response</code> has
147: * been committed then this will return quietly. Typically there
148: * will be an <code>IOException</code> writing the content body if
149: * the stream has been closed. This will not report such exceptions.
150: *
151: * @param req the <code>Request</code> object to be processed
152: * @param resp the <code>Response</code> object to be processed
153: * @param report this is used to describe the change in status
154: */
155: public void handle(Request req, Response resp, Report report) {
156: try {
157: if (!resp.isCommitted()) {
158: resp.reset();
159: process(req, resp, report);
160: }
161: resp.getOutputStream().close();
162: } catch (IOException e) {
163: } catch (Exception e) {
164: e.printStackTrace();
165: }
166: }
167:
168: /**
169: * This method is used to handle the HTTP status reports so that
170: * if any <code>Exception</code> occurs the <code>handle</code>
171: * method can capture and deal with the exception.
172: * <p>
173: * Subclasses should treat this as the <code>handle</code> method
174: * of the <code>ProtocolHandler</code>. Exceptions that cannot be
175: * recovered from, particularly <code>RuntimeException</code>'s
176: * should be left propagate so the <code>handle</code> method can
177: * deal with the <code>Exception</code> appropriately.
178: *
179: * @param req the <code>Request</code> object to be processed
180: * @param resp the <code>Response</code> object to be processed
181: * @param code this is the HTTP status code of the response
182: *
183: * @exception Exception this can throw an error for anything
184: */
185: protected void process(Request req, Response resp, int code)
186: throws Exception {
187: process(req, resp, new StatusReport(code));
188: }
189:
190: /**
191: * This method is used to handle the HTTP status reports so that
192: * if any <code>Exception</code> occurs the <code>handle</code>
193: * method can capture and deal with the exception.
194: * <p>
195: * Subclasses should treat this as the <code>handle</code> method
196: * of the <code>ProtocolHandler</code>. Exceptions that cannot be
197: * recovered from, particularly <code>RuntimeException</code>'s
198: * should be left propagate so the <code>handle</code> method can
199: * deal with the <code>Exception</code> appropriately.
200: *
201: * @param req the <code>Request</code> object to be processed
202: * @param resp the <code>Response</code> object to be processed
203: * @param report this is used to describe the change in status
204: *
205: * @exception Exception this can throw an error for anything
206: */
207: protected void process(Request req, Response resp, Report report)
208: throws Exception {
209: Format format = context.getFormat();
210: byte[] page = format.getMessage(context, req.getURI(), report);
211:
212: resp.setCode(report.getCode());
213: resp.setText(report.getText());
214: resp.setDate("Date", System.currentTimeMillis());
215: resp.setContentLength(page.length);
216: resp.set("Content-Type", format.getContentType());
217: resp.getOutputStream().write(page);
218: resp.getOutputStream().close();
219: }
220:
221: /**
222: * This method is used to handle the HTTP transaction by subclasses
223: * of the <code>Component</code>. This is used so that if there
224: * are any <code>Exception</code>'s thrown while processing the
225: * HTTP transaction they can be captured and the HTTP status line
226: * will convey the status to the client.
227: * <p>
228: * Subclasses should treat this as the <code>handle</code> method
229: * of the <code>ProtocolHandler</code>. Exceptions that cannot be
230: * recovered from, particularly <code>RuntimeException</code>'s
231: * should be left propagate so the <code>handle</code> method can
232: * prepare an appropriate response.
233: *
234: * @param req the <code>Request</code> object to be processed
235: * @param resp the <code>Response</code> object to be processed
236: *
237: * @exception Exception this can throw an error for anything
238: */
239: protected abstract void process(Request req, Response resp)
240: throws Exception;
241: }
|